Skip to content

Commit 8c93f91

Browse files
committed
add latest comment id to url
1 parent e42fd54 commit 8c93f91

15 files changed

+759
-315
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,4 @@ temp/
7878

7979
dist/
8080
build/
81+
.vscode/settings.json

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@
124124
"react-transition-group": "^4.4.1",
125125
"tailwindcss": "^2.0.2",
126126
"ts-loader": "^8.0.12",
127-
"typescript": "^4.1.3"
127+
"typescript": "^4.6.2"
128128
},
129129
"devDependencies": {
130130
"@testing-library/react": "^11.2.2",

src/__mocks__/electron.js

+18-10
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,26 @@ window.localStorage = {
2727

2828
window.alert = jest.fn();
2929

30-
const browserWindow = {
31-
loadURL: jest.fn(),
32-
webContents: {
30+
let instance;
31+
32+
class BrowserWindow {
33+
constructor() {
34+
if(!instance){
35+
instance = this;
36+
}
37+
return instance;
38+
}
39+
loadURL = jest.fn();
40+
webContents = {
3341
on: () => {},
3442
session: {
3543
clearStorageData: jest.fn(),
3644
},
37-
},
38-
on: () => {},
39-
close: jest.fn(),
40-
hide: jest.fn(),
41-
destroy: jest.fn(),
45+
};
46+
on(){};
47+
close = jest.fn();
48+
hide = jest.fn();
49+
destroy = jest.fn();
4250
};
4351

4452
const dialog = {
@@ -47,7 +55,7 @@ const dialog = {
4755

4856
module.exports = {
4957
remote: {
50-
BrowserWindow: () => browserWindow,
58+
BrowserWindow: BrowserWindow,
5159
dialog: dialog,
5260
process: {
5361
platform: 'darwin',
@@ -57,7 +65,7 @@ module.exports = {
5765
getLoginItemSettings: jest.fn(),
5866
setLoginItemSettings: () => {},
5967
},
60-
getCurrentWindow: jest.fn(() => browserWindow),
68+
getCurrentWindow: jest.fn(() => instance || new BrowserWindow),
6169
},
6270
ipcRenderer: {
6371
send: jest.fn(),

src/__mocks__/mockedData.ts

+114-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AccountNotifications, EnterpriseAccount } from '../types';
2-
import { Notification, Repository, User } from '../typesGithub';
2+
import { Notification, Repository, User, GraphQLSearch } from '../typesGithub';
33

44
export const mockedEnterpriseAccounts: EnterpriseAccount[] = [
55
{
@@ -274,3 +274,116 @@ export const mockedSingleAccountNotifications: AccountNotifications[] = [
274274
notifications: [mockedSingleNotification],
275275
},
276276
];
277+
278+
export const mockedGraphQLResponse: GraphQLSearch = {
279+
"data": {
280+
"data": {
281+
"search": {
282+
"edges": [
283+
{
284+
"node": {
285+
"viewerSubscription": "SUBSCRIBED",
286+
"title": "1.16.0",
287+
"url": "https://github.com/manosim/notifications-test/discussions/612",
288+
"comments": {
289+
"edges": [
290+
{
291+
"node": {
292+
"databaseId": 2215656,
293+
"createdAt": "2022-02-20T18:33:39Z",
294+
"replies": {
295+
"edges": []
296+
}
297+
}
298+
},
299+
{
300+
"node": {
301+
"databaseId": 2217789,
302+
"createdAt": "2022-02-21T03:30:42Z",
303+
"replies": {
304+
"edges": []
305+
}
306+
}
307+
},
308+
{
309+
"node": {
310+
"databaseId": 2223243,
311+
"createdAt": "2022-02-21T18:26:27Z",
312+
"replies": {
313+
"edges": [
314+
{
315+
"node": {
316+
"databaseId": 2232922,
317+
"createdAt": "2022-02-23T00:57:58Z"
318+
}
319+
}
320+
]
321+
}
322+
}
323+
},
324+
{
325+
"node": {
326+
"databaseId": 2232921,
327+
"createdAt": "2022-02-23T00:57:49Z",
328+
"replies": {
329+
"edges": []
330+
}
331+
}
332+
},
333+
{
334+
"node": {
335+
"databaseId": 2258799,
336+
"createdAt": "2022-02-27T01:22:20Z",
337+
"replies": {
338+
"edges": [
339+
{
340+
"node": {
341+
"databaseId": 2300902,
342+
"createdAt": "2022-03-05T17:43:52Z"
343+
}
344+
}
345+
]
346+
}
347+
}
348+
},
349+
{
350+
"node": {
351+
"databaseId": 2297637,
352+
"createdAt": "2022-03-04T20:39:44Z",
353+
"replies": {
354+
"edges": [
355+
{
356+
"node": {
357+
"databaseId": 2300893,
358+
"createdAt": "2022-03-05T17:41:04Z"
359+
}
360+
}
361+
]
362+
}
363+
}
364+
},
365+
{
366+
"node": {
367+
"databaseId": 2299763,
368+
"createdAt": "2022-03-05T11:05:42Z",
369+
"replies": {
370+
"edges": [
371+
{
372+
"node": {
373+
"databaseId": 2300895,
374+
"createdAt": "2022-03-05T17:41:44Z"
375+
}
376+
}
377+
]
378+
}
379+
}
380+
}
381+
]
382+
}
383+
}
384+
}
385+
]
386+
}
387+
}
388+
}
389+
}

src/components/NotificationRow.tsx

+2-24
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
import { openExternalLink } from '../utils/comms';
2-
31
import React, { useCallback, useContext } from 'react';
42
import { formatDistanceToNow, parseISO } from 'date-fns';
53
import { CheckIcon, MuteIcon } from '@primer/octicons-react';
64

75
import { formatReason, getNotificationTypeIcon } from '../utils/github-api';
8-
import { generateGitHubWebUrl, getDiscussionUrl } from '../utils/helpers';
6+
import { openInBrowser } from '../utils/helpers';
97
import { Notification } from '../typesGithub';
108
import { AppContext } from '../context/App';
119

@@ -33,27 +31,7 @@ export const NotificationRow: React.FC<IProps> = ({
3331
}
3432
}, [settings]);
3533

36-
const openBrowser = useCallback(() => {
37-
// Some Notification types from GitHub are missing urls in their subjects.
38-
if (notification.subject.url) {
39-
const url = generateGitHubWebUrl(
40-
notification.subject.url,
41-
notification.id,
42-
accounts.user?.id
43-
);
44-
openExternalLink(url);
45-
} else if (notification.subject.type === 'Discussion') {
46-
getDiscussionUrl(notification, accounts.token).then(url =>
47-
openExternalLink(
48-
generateGitHubWebUrl(
49-
url || `${notification.repository.url}/discussions`,
50-
notification.id,
51-
accounts.user?.id
52-
)
53-
)
54-
);
55-
}
56-
}, [notification]);
34+
const openBrowser = useCallback(() => openInBrowser(notification, accounts), [notification]);
5735

5836
const unsubscribe = (event: React.MouseEvent<HTMLElement>) => {
5937
// Don't trigger onClick of parent element.

src/routes/__snapshots__/LoginWithToken.test.tsx.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ exports[`routes/LoginWithToken.js renders correctly 1`] = `
8484
<span
8585
className="underline font-extrabold text-yellow-500"
8686
>
87-
read:user, notifications
87+
read:user, notifications, repo
8888
8989
</span>
9090
scopes.

src/typesGithub.ts

+43
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export type SubjectType =
2121
| 'Release'
2222
| 'RepositoryVulnerabilityAlert';
2323

24+
export type ViewerSubscription =
25+
| 'IGNORED'
26+
| 'SUBSCRIBED'
27+
| 'UNSUBSCRIBED'
28+
2429
export interface Notification {
2530
id: string;
2631
unread: boolean;
@@ -115,3 +120,41 @@ export interface Subject {
115120
latest_comment_url?: string;
116121
type: SubjectType;
117122
}
123+
124+
export interface GraphQLSearch {
125+
data: {
126+
data: {
127+
search: {
128+
edges: DiscussionEdge[]
129+
}
130+
}
131+
}
132+
}
133+
134+
export interface DiscussionEdge {
135+
node: {
136+
viewerSubscription: ViewerSubscription;
137+
title: string;
138+
url: string;
139+
comments: {
140+
edges: DiscussionCommentEdge[]
141+
}
142+
}
143+
}
144+
145+
export interface DiscussionCommentEdge {
146+
node: {
147+
databaseId: string|number;
148+
createdAt: string;
149+
replies: {
150+
edges: DiscussionSubcommentEdge[]
151+
}
152+
}
153+
}
154+
155+
export interface DiscussionSubcommentEdge {
156+
node: {
157+
databaseId: string|number;
158+
createdAt: string;
159+
}
160+
}

src/utils/auth.test.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
import { AxiosPromise, AxiosResponse } from 'axios';
22

3-
const { remote } = require('electron');
4-
const BrowserWindow = remote.BrowserWindow;
3+
import { remote } from 'electron';
4+
const browserWindow = new remote.BrowserWindow
55

66
import * as auth from './auth';
77
import * as apiRequests from './api-requests';
88
import { AuthState } from '../types';
99

1010
describe('utils/auth.tsx', () => {
1111
describe('authGitHub', () => {
12-
const loadURLMock = jest.spyOn(new BrowserWindow(), 'loadURL');
12+
const loadURLMock = jest.spyOn(browserWindow, 'loadURL');
1313

1414
beforeEach(() => {
1515
loadURLMock.mockReset();
1616
});
1717

1818
it('should call authGithub - success', async () => {
19-
spyOn(new BrowserWindow().webContents, 'on').and.callFake(
19+
spyOn(browserWindow.webContents, 'on').and.callFake(
2020
(event, callback) => {
2121
if (event === 'will-redirect') {
2222
const event = new Event('will-redirect');
@@ -30,19 +30,19 @@ describe('utils/auth.tsx', () => {
3030
expect(res.authCode).toBe('123-456');
3131

3232
expect(
33-
new BrowserWindow().webContents.session.clearStorageData
33+
browserWindow.webContents.session.clearStorageData
3434
).toHaveBeenCalledTimes(1);
3535

3636
expect(loadURLMock).toHaveBeenCalledTimes(1);
3737
expect(loadURLMock).toHaveBeenCalledWith(
38-
'https://github.com/login/oauth/authorize?client_id=FAKE_CLIENT_ID_123&scope=read:user,notifications'
38+
'https://github.com/login/oauth/authorize?client_id=FAKE_CLIENT_ID_123&scope=read:user,notifications,repo'
3939
);
4040

41-
expect(new BrowserWindow().destroy).toHaveBeenCalledTimes(1);
41+
expect(browserWindow.destroy).toHaveBeenCalledTimes(1);
4242
});
4343

4444
it('should call authGithub - failure', async () => {
45-
spyOn(new BrowserWindow().webContents, 'on').and.callFake(
45+
spyOn(browserWindow.webContents, 'on').and.callFake(
4646
(event, callback) => {
4747
if (event === 'will-redirect') {
4848
const event = new Event('will-redirect');

src/utils/constants.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export const Constants = {
22
// GitHub OAuth
3-
AUTH_SCOPE: ['read:user', 'notifications'],
3+
AUTH_SCOPE: ['read:user', 'notifications', 'repo'],
44

55
DEFAULT_AUTH_OPTIONS: {
66
hostname: 'github.com',

0 commit comments

Comments
 (0)