-
Notifications
You must be signed in to change notification settings - Fork 285
Expand file tree
/
Copy pathdiscussion.ts
More file actions
143 lines (122 loc) · 4.03 KB
/
discussion.ts
File metadata and controls
143 lines (122 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import type { FC } from 'react';
import type { OcticonProps } from '@primer/octicons-react';
import {
CommentDiscussionIcon,
DiscussionClosedIcon,
DiscussionDuplicateIcon,
DiscussionOutdatedIcon,
} from '@primer/octicons-react';
import { differenceInMilliseconds } from 'date-fns';
import {
type GitifyDiscussionState,
type GitifyNotification,
type GitifySubject,
IconColor,
type Link,
type SettingsState,
} from '../../../types';
import { fetchDiscussionByNumber } from '../../api/client';
import type {
CommentFieldsFragment,
DiscussionCommentFieldsFragment,
DiscussionDetailsFragment,
} from '../../api/graphql/generated/graphql';
import { DefaultHandler, defaultHandler } from './default';
import { getNotificationAuthor } from './utils';
class DiscussionHandler extends DefaultHandler {
override readonly supportsMergedQueryEnrichment = true;
override async enrich(
notification: GitifyNotification,
_settings: SettingsState,
fetchedData?: DiscussionDetailsFragment,
): Promise<Partial<GitifySubject>> {
const discussion =
fetchedData ??
(await fetchDiscussionByNumber(notification)).repository?.discussion;
let discussionState: GitifyDiscussionState = 'OPEN';
if (discussion.isAnswered) {
discussionState = 'ANSWERED';
}
if (discussion.stateReason) {
discussionState = discussion.stateReason;
}
const latestDiscussionComment = getClosestDiscussionCommentOrReply(
notification,
discussion.comments.nodes,
);
const discussionReactionCount =
latestDiscussionComment?.reactions.totalCount ??
discussion.reactions.totalCount;
const discussionReactionGroup =
latestDiscussionComment?.reactionGroups ?? discussion.reactionGroups;
return {
number: discussion.number,
state: discussionState,
user: getNotificationAuthor([
latestDiscussionComment?.author,
discussion.author,
]),
commentCount: discussion.comments.totalCount,
labels:
discussion.labels?.nodes.map((label) => ({
name: label.name,
color: label.color,
})) ?? [],
htmlUrl: latestDiscussionComment?.url ?? discussion.url,
reactionsCount: discussionReactionCount,
reactionGroups: discussionReactionGroup,
};
}
override iconType(notification: GitifyNotification): FC<OcticonProps> {
switch (notification.subject.state as GitifyDiscussionState) {
case 'DUPLICATE':
return DiscussionDuplicateIcon;
case 'OUTDATED':
return DiscussionOutdatedIcon;
case 'RESOLVED':
return DiscussionClosedIcon;
default:
return CommentDiscussionIcon;
}
}
override iconColor(notification: GitifyNotification): IconColor {
switch (notification.subject.state) {
case 'ANSWERED':
return IconColor.GREEN;
case 'RESOLVED':
return IconColor.PURPLE;
default:
return defaultHandler.iconColor(notification);
}
}
override defaultUrl(notification: GitifyNotification): Link {
const url = new URL(defaultHandler.defaultUrl(notification));
url.pathname += '/discussions';
return url.href as Link;
}
}
export const discussionHandler = new DiscussionHandler();
export function getClosestDiscussionCommentOrReply(
notification: GitifyNotification,
comments: DiscussionCommentFieldsFragment[],
): CommentFieldsFragment | null {
if (!comments || comments.length === 0) {
return null;
}
const targetTimestamp = notification.updatedAt;
const allCommentsAndReplies = comments.flatMap((comment) => [
...comment.replies.nodes,
comment,
]);
// Find the closest match using the target timestamp
const closestComment = allCommentsAndReplies.reduce((prev, curr) => {
const prevDiff = Math.abs(
differenceInMilliseconds(prev.createdAt, targetTimestamp),
);
const currDiff = Math.abs(
differenceInMilliseconds(curr.createdAt, targetTimestamp),
);
return currDiff < prevDiff ? curr : prev;
}, allCommentsAndReplies[0]);
return closestComment;
}