Skip to content
Merged
4 changes: 4 additions & 0 deletions src/__mocks__/mockedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ export const mockedGraphQLResponse: GraphQLSearch<DiscussionSearchResultNode> =
{
viewerSubscription: 'SUBSCRIBED',
title: '1.16.0',
isAnswered: false,
stateReason: null,
url: 'https://github.com/manosim/notifications-test/discussions/612',
comments: {
nodes: [
Expand Down Expand Up @@ -369,6 +371,8 @@ export const mockedGraphQLResponse: GraphQLSearch<DiscussionSearchResultNode> =
{
viewerSubscription: 'IGNORED',
title: '1.16.0',
isAnswered: false,
stateReason: null,
url: 'https://github.com/manosim/notifications-test/discussions/612',
comments: {
nodes: [
Expand Down
12 changes: 5 additions & 7 deletions src/hooks/useNotifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
],
},
Expand Down
7 changes: 1 addition & 6 deletions src/typesGithub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,16 +248,11 @@ export interface GraphQLSearch<T> {
};
}

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[];
Expand Down
2 changes: 1 addition & 1 deletion src/utils/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ describe('utils/helpers.ts', () => {

const requestPromise = new Promise((resolve) =>
resolve({
data: {},
data: { data: { search: { nodes: [] } } },
} as AxiosResponse),
) as AxiosPromise;

Expand Down
105 changes: 67 additions & 38 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,39 +126,80 @@ async function getDiscussionUrl(
): Promise<string> {
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<DiscussionSearchResultNode | null> {
const response: GraphQLSearch<DiscussionSearchResultNode> =
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
}
}
}
}
}
}
}
}
}`,
`,
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,
) || [];

Expand All @@ -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,
Expand Down
38 changes: 3 additions & 35 deletions src/utils/state.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { formatSearchQueryString } from './helpers';
import { fetchDiscussion } from './helpers';
import {
CheckSuiteAttributes,
CheckSuiteStatus,
DiscussionStateSearchResultNode,
DiscussionStateType,
GraphQLSearch,
Issue,
IssueStateReasonType,
IssueStateType,
Expand Down Expand Up @@ -84,39 +82,9 @@ export async function getDiscussionState(
notification: Notification,
token: string,
): Promise<DiscussionStateType> {
const response: GraphQLSearch<DiscussionStateSearchResultNode> =
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';
}
Expand Down