Skip to content

Commit 5e086ae

Browse files
afonsojramossetchy
andauthored
refactor: use GitifyNotification type with transformation layer (#2484)
* refactor: use GitifyNotification type with transformation layer Introduce a clean separation between raw GitHub API types and internal Gitify notification types: - Add transform.ts at API boundary to convert raw GitHub responses - Define GitifyNotification, GitifySubject, GitifyRepository, GitifyOwner types with camelCase properties - Update all components, handlers, filters, and utilities to use new types - Update GraphQL schema aliases for consistent property naming - Remove Notification type alias from typesGitHub.ts Closes #828 * further type refactoring Signed-off-by: Adam Setch <[email protected]> * further type refactoring Signed-off-by: Adam Setch <[email protected]> * further type refactoring Signed-off-by: Adam Setch <[email protected]> * further type refactoring Signed-off-by: Adam Setch <[email protected]> --------- Signed-off-by: Adam Setch <[email protected]> Co-authored-by: Adam Setch <[email protected]>
1 parent 3a750e4 commit 5e086ae

File tree

82 files changed

+1033
-1255
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1033
-1255
lines changed

src/renderer/__mocks__/notifications-mocks.ts

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { Constants } from '../constants';
22
import type {
33
AccountNotifications,
4+
GitifyNotification,
45
GitifyNotificationState,
6+
GitifyRepository,
7+
GitifySubject,
58
Hostname,
6-
} from '../types';
7-
import type {
8-
Notification,
9-
Repository,
10-
Subject,
9+
Link,
1110
SubjectType,
12-
} from '../typesGitHub';
11+
} from '../types';
1312
import {
1413
mockEnterpriseNotifications,
1514
mockGitHubNotifications,
@@ -47,21 +46,21 @@ export function createMockSubject(mocks: {
4746
title?: string;
4847
type?: SubjectType;
4948
state?: GitifyNotificationState;
50-
}): Subject {
49+
}): GitifySubject {
5150
return {
5251
title: mocks.title ?? 'Mock Subject',
5352
type: mocks.type ?? ('Unknown' as SubjectType),
5453
state: mocks.state ?? ('Unknown' as GitifyNotificationState),
5554
url: null,
56-
latest_comment_url: null,
55+
latestCommentUrl: null,
5756
};
5857
}
5958

6059
export function createPartialMockNotification(
61-
subject: Partial<Subject>,
62-
repository?: Partial<Repository>,
63-
): Notification {
64-
const mockNotification: Partial<Notification> = {
60+
subject: Partial<GitifySubject>,
61+
repository?: Partial<GitifyRepository>,
62+
): GitifyNotification {
63+
const mockNotification: Partial<GitifyNotification> = {
6564
account: {
6665
method: 'Personal Access Token',
6766
platform: 'GitHub Cloud',
@@ -70,28 +69,30 @@ export function createPartialMockNotification(
7069
user: mockGitifyUser,
7170
hasRequiredScopes: true,
7271
},
73-
subject: subject as Subject,
72+
subject: subject as GitifySubject,
7473
repository: {
7574
name: 'notifications-test',
76-
full_name: 'gitify-app/notifications-test',
77-
html_url: 'https://github.com/gitify-app/notifications-test',
75+
fullName: 'gitify-app/notifications-test',
76+
htmlUrl: 'https://github.com/gitify-app/notifications-test' as Link,
7877
owner: {
7978
login: 'gitify-app',
79+
avatarUrl: 'https://avatars.githubusercontent.com/u/1' as Link,
80+
type: 'Organization',
8081
},
8182
...repository,
82-
} as Repository,
83+
} as GitifyRepository,
8384
};
8485

85-
return mockNotification as Notification;
86+
return mockNotification as GitifyNotification;
8687
}
8788

8889
export function createMockNotificationForRepoName(
8990
id: string,
9091
repoFullName: string | null,
91-
): Notification {
92+
): GitifyNotification {
9293
return {
9394
id,
94-
repository: repoFullName ? { full_name: repoFullName } : null,
95+
repository: repoFullName ? { fullName: repoFullName } : null,
9596
account: mockGitHubCloudAccount,
96-
} as Notification;
97+
} as GitifyNotification;
9798
}
Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { GitifyUser, Link } from '../types';
2-
import type { User } from '../typesGitHub';
1+
import type { GitifyNotificationUser, GitifyUser, Link } from '../types';
2+
import type { RawUser } from '../utils/api/types';
33

44
export const mockGitifyUser: GitifyUser = {
55
login: 'octocat',
@@ -8,13 +8,24 @@ export const mockGitifyUser: GitifyUser = {
88
avatar: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
99
};
1010

11-
export function createPartialMockUser(login: string): User {
12-
const mockUser: Partial<User> = {
11+
export function createPartialMockUser(login: string): RawUser {
12+
const mockUser: Partial<RawUser> = {
1313
login: login,
1414
html_url: `https://github.com/${login}` as Link,
1515
avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
1616
type: 'User',
1717
};
1818

19-
return mockUser as User;
19+
return mockUser as RawUser;
20+
}
21+
22+
export function createMockNotificationUser(
23+
login: string,
24+
): GitifyNotificationUser {
25+
return {
26+
login: login,
27+
htmlUrl: `https://github.com/${login}` as Link,
28+
avatarUrl: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
29+
type: 'User',
30+
};
2031
}

src/renderer/components/avatars/AvatarWithFallback.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import { useState } from 'react';
33

44
import { Avatar, Stack, Truncate } from '@primer/react';
55

6-
import { type Link, Size } from '../../types';
7-
import type { UserType } from '../../typesGitHub';
6+
import { type Link, Size, type UserType } from '../../types';
87
import { getDefaultUserIcon } from '../../utils/icons';
98
import { isNonHumanUser } from '../../utils/notifications/filters/userType';
109

src/renderer/components/metrics/MetricGroup.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { renderWithAppContext } from '../../__helpers__/test-utils';
22
import { mockSettings } from '../../__mocks__/state-mocks';
3+
import type { GitifyMilestone } from '../../types';
34
import { mockSingleNotification } from '../../utils/api/__mocks__/response-mocks';
4-
import type { MilestoneFieldsFragment } from '../../utils/api/graphql/generated/graphql';
55
import { MetricGroup } from './MetricGroup';
66

77
describe('renderer/components/metrics/MetricGroup.tsx', () => {
@@ -104,7 +104,7 @@ describe('renderer/components/metrics/MetricGroup.tsx', () => {
104104
mockNotification.subject.milestone = {
105105
title: 'Milestone 1',
106106
state: 'OPEN',
107-
} as MilestoneFieldsFragment;
107+
} as GitifyMilestone;
108108

109109
const props = {
110110
notification: mockNotification,
@@ -119,7 +119,7 @@ describe('renderer/components/metrics/MetricGroup.tsx', () => {
119119
mockNotification.subject.milestone = {
120120
title: 'Milestone 1',
121121
state: 'CLOSED',
122-
} as MilestoneFieldsFragment;
122+
} as GitifyMilestone;
123123

124124
const props = {
125125
notification: mockNotification,

src/renderer/components/metrics/MetricGroup.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,12 @@ import {
88
} from '@primer/octicons-react';
99

1010
import { useAppContext } from '../../context/App';
11-
import { IconColor } from '../../types';
12-
import type { Notification } from '../../typesGitHub';
11+
import { type GitifyNotification, IconColor } from '../../types';
1312
import { getPullRequestReviewIcon } from '../../utils/icons';
1413
import { MetricPill } from './MetricPill';
1514

1615
interface MetricGroupProps {
17-
notification: Notification;
16+
notification: GitifyNotification;
1817
}
1918

2019
export const MetricGroup: FC<MetricGroupProps> = ({

src/renderer/components/notifications/AccountNotifications.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@ import { GitPullRequestIcon, IssueOpenedIcon } from '@primer/octicons-react';
44
import { Button, Stack } from '@primer/react';
55

66
import { useAppContext } from '../../context/App';
7-
import { type Account, type GitifyError, Size } from '../../types';
8-
import type { Notification } from '../../typesGitHub';
7+
import {
8+
type Account,
9+
type GitifyError,
10+
type GitifyNotification,
11+
Size,
12+
} from '../../types';
913
import { hasMultipleAccounts } from '../../utils/auth/utils';
1014
import { cn } from '../../utils/cn';
1115
import { getChevronDetails } from '../../utils/helpers';
@@ -28,7 +32,7 @@ import { RepositoryNotifications } from './RepositoryNotifications';
2832

2933
interface AccountNotificationsProps {
3034
account: Account;
31-
notifications: Notification[];
35+
notifications: GitifyNotification[];
3236
error: GitifyError | null;
3337
showAccountHeader: boolean;
3438
}

src/renderer/components/notifications/NotificationFooter.test.tsx

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import userEvent from '@testing-library/user-event';
33

44
import { renderWithAppContext } from '../../__helpers__/test-utils';
55
import { mockGitHubCloudAccount } from '../../__mocks__/account-mocks';
6-
import type { Link } from '../../types';
7-
import type { UserType } from '../../typesGitHub';
6+
import type { GitifyNotificationUser, Link } from '../../types';
87
import { mockSingleNotification } from '../../utils/api/__mocks__/response-mocks';
98
import * as comms from '../../utils/comms';
109
import { NotificationFooter } from './NotificationFooter';
@@ -28,19 +27,6 @@ describe('renderer/components/notifications/NotificationFooter.tsx', () => {
2827
expect(tree).toMatchSnapshot();
2928
});
3029

31-
it('should render itself & its children when last_read_at is null', async () => {
32-
const mockNotification = mockSingleNotification;
33-
mockNotification.last_read_at = null;
34-
35-
const props = {
36-
notification: mockNotification,
37-
};
38-
39-
const tree = renderWithAppContext(<NotificationFooter {...props} />);
40-
41-
expect(tree).toMatchSnapshot();
42-
});
43-
4430
describe('security alerts should use github icon for avatar', () => {
4531
it('Repository Dependabot Alerts Thread', async () => {
4632
const mockNotification = mockSingleNotification;
@@ -94,10 +80,10 @@ describe('renderer/components/notifications/NotificationFooter.tsx', () => {
9480
...mockSingleNotification.subject,
9581
user: {
9682
login: 'some-user',
97-
html_url: 'https://github.com/some-user' as Link,
98-
avatar_url:
83+
htmlUrl: 'https://github.com/some-user' as Link,
84+
avatarUrl:
9985
'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
100-
type: 'User' as UserType,
86+
type: 'User' as GitifyNotificationUser['type'],
10187
},
10288
reviews: null,
10389
},
@@ -111,7 +97,7 @@ describe('renderer/components/notifications/NotificationFooter.tsx', () => {
11197

11298
expect(openExternalLinkSpy).toHaveBeenCalledTimes(1);
11399
expect(openExternalLinkSpy).toHaveBeenCalledWith(
114-
props.notification.subject.user.html_url,
100+
props.notification.subject.user.htmlUrl,
115101
);
116102
});
117103
});

src/renderer/components/notifications/NotificationFooter.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@ import type { FC, MouseEvent } from 'react';
22

33
import { RelativeTime, Stack, Text } from '@primer/react';
44

5-
import { Opacity, Size } from '../../types';
6-
import type { Notification } from '../../typesGitHub';
5+
import { type GitifyNotification, Opacity, Size } from '../../types';
76
import { cn } from '../../utils/cn';
87
import { openUserProfile } from '../../utils/links';
98
import { getReasonDetails } from '../../utils/reason';
109
import { AvatarWithFallback } from '../avatars/AvatarWithFallback';
1110
import { MetricGroup } from '../metrics/MetricGroup';
1211

1312
interface NotificationFooterProps {
14-
notification: Notification;
13+
notification: GitifyNotification;
1514
}
1615

1716
export const NotificationFooter: FC<NotificationFooterProps> = ({
@@ -41,7 +40,7 @@ export const NotificationFooter: FC<NotificationFooterProps> = ({
4140
<AvatarWithFallback
4241
alt={notification.subject.user.login}
4342
size={Size.SMALL}
44-
src={notification.subject.user.avatar_url}
43+
src={notification.subject.user.avatarUrl}
4544
userType={notification.subject.user.type}
4645
/>
4746
</button>
@@ -61,7 +60,7 @@ export const NotificationFooter: FC<NotificationFooterProps> = ({
6160
<Text className="pr-1" title={reason.description}>
6261
{reason.title}
6362
</Text>
64-
<RelativeTime datetime={notification.updated_at} />
63+
<RelativeTime datetime={notification.updatedAt} />
6564
</Stack>
6665

6766
<MetricGroup notification={notification} />

src/renderer/components/notifications/NotificationHeader.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe('renderer/components/notifications/NotificationHeader.tsx', () => {
8787

8888
expect(openExternalLinkSpy).toHaveBeenCalledTimes(1);
8989
expect(openExternalLinkSpy).toHaveBeenCalledWith(
90-
props.notification.repository.html_url,
90+
props.notification.repository.htmlUrl,
9191
);
9292
});
9393
});

src/renderer/components/notifications/NotificationHeader.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,21 @@ import type { FC, MouseEvent } from 'react';
33
import { Stack } from '@primer/react';
44

55
import { useAppContext } from '../../context/App';
6-
import { GroupBy, Opacity, Size } from '../../types';
7-
import type { Notification } from '../../typesGitHub';
6+
import { type GitifyNotification, GroupBy, Opacity, Size } from '../../types';
87
import { cn } from '../../utils/cn';
98
import { openRepository } from '../../utils/links';
109
import { AvatarWithFallback } from '../avatars/AvatarWithFallback';
1110

1211
interface NotificationHeaderProps {
13-
notification: Notification;
12+
notification: GitifyNotification;
1413
}
1514

1615
export const NotificationHeader: FC<NotificationHeaderProps> = ({
1716
notification,
1817
}: NotificationHeaderProps) => {
1918
const { settings } = useAppContext();
2019

21-
const repoSlug = notification.repository.full_name;
20+
const repoSlug = notification.repository.fullName;
2221

2322
const notificationNumber = notification.subject?.number
2423
? `#${notification.subject.number}`
@@ -45,7 +44,7 @@ export const NotificationHeader: FC<NotificationHeaderProps> = ({
4544
alt={repoSlug}
4645
name={repoSlug}
4746
size={Size.SMALL}
48-
src={notification.repository.owner.avatar_url}
47+
src={notification.repository.owner.avatarUrl}
4948
userType={notification.repository.owner.type}
5049
/>
5150
</button>

0 commit comments

Comments
 (0)