diff --git a/src/components/notification/NotificationFooter.test.tsx b/src/components/notification/NotificationFooter.test.tsx index 200b919bd..fd01cc043 100644 --- a/src/components/notification/NotificationFooter.test.tsx +++ b/src/components/notification/NotificationFooter.test.tsx @@ -59,7 +59,49 @@ describe('components/notification/NotificationFooter.tsx', () => { expect(tree).toMatchSnapshot(); }); - it('should render itself & its children without avatar', async () => { + describe('security alerts should use github icon for avatar', () => { + it('Repository Dependabot Alerts Thread', async () => { + jest + .spyOn(global.Date, 'now') + .mockImplementation(() => new Date('2024').valueOf()); + + const mockNotification = mockSingleNotification; + mockNotification.subject.type = 'RepositoryDependabotAlertsThread'; + + const props = { + notification: mockNotification, + }; + + const tree = render( + + + , + ); + expect(tree).toMatchSnapshot(); + }); + + it('Repository Vulnerability Alert', async () => { + jest + .spyOn(global.Date, 'now') + .mockImplementation(() => new Date('2024').valueOf()); + + const mockNotification = mockSingleNotification; + mockNotification.subject.type = 'RepositoryVulnerabilityAlert'; + + const props = { + notification: mockNotification, + }; + + const tree = render( + + + , + ); + expect(tree).toMatchSnapshot(); + }); + }); + + it('should default to known avatar if no user found', async () => { jest .spyOn(global.Date, 'now') .mockImplementation(() => new Date('2024').valueOf()); diff --git a/src/components/notification/NotificationFooter.tsx b/src/components/notification/NotificationFooter.tsx index fa883512e..ae075d473 100644 --- a/src/components/notification/NotificationFooter.tsx +++ b/src/components/notification/NotificationFooter.tsx @@ -1,4 +1,4 @@ -import { FeedPersonIcon } from '@primer/octicons-react'; +import { FeedPersonIcon, MarkGithubIcon } from '@primer/octicons-react'; import type { FC, MouseEvent } from 'react'; import { IconColor, Opacity, Size } from '../../types'; import type { Notification } from '../../typesGitHub'; @@ -50,7 +50,12 @@ export const NotificationFooter: FC = ({ ) : (
- + {notification.subject.type === 'RepositoryDependabotAlertsThread' || + notification.subject.type === 'RepositoryVulnerabilityAlert' ? ( + + ) : ( + + )}
)}
{reason.title}
diff --git a/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap b/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap index 5d59c1f55..7d462c36c 100644 --- a/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap +++ b/src/components/notification/__snapshots__/NotificationFooter.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`components/notification/NotificationFooter.tsx should render itself & its children 1`] = ` +exports[`components/notification/NotificationFooter.tsx security alerts should use github icon for avatar Repository Dependabot Alerts Thread 1`] = ` { "asFragment": [Function], "baseElement": @@ -209,7 +209,7 @@ exports[`components/notification/NotificationFooter.tsx should render itself & i } `; -exports[`components/notification/NotificationFooter.tsx should render itself & its children when last_read_at is null 1`] = ` +exports[`components/notification/NotificationFooter.tsx security alerts should use github icon for avatar Repository Vulnerability Alert 1`] = ` { "asFragment": [Function], "baseElement": @@ -418,7 +418,7 @@ exports[`components/notification/NotificationFooter.tsx should render itself & i } `; -exports[`components/notification/NotificationFooter.tsx should render itself & its children without avatar 1`] = ` +exports[`components/notification/NotificationFooter.tsx should default to known avatar if no user found 1`] = ` { "asFragment": [Function], "baseElement": @@ -429,7 +429,7 @@ exports[`components/notification/NotificationFooter.tsx should render itself & i
@@ -510,7 +510,7 @@ exports[`components/notification/NotificationFooter.tsx should render itself & i
@@ -636,3 +636,421 @@ exports[`components/notification/NotificationFooter.tsx should render itself & i "unmount": [Function], } `; + +exports[`components/notification/NotificationFooter.tsx should render itself & its children 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+ +
+ Updated +
+
+ 7 years ago +
+
+ + +
+
+
+ , + "container":
+
+ +
+ Updated +
+
+ 7 years ago +
+
+ + +
+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; + +exports[`components/notification/NotificationFooter.tsx should render itself & its children when last_read_at is null 1`] = ` +{ + "asFragment": [Function], + "baseElement": +
+
+ +
+ Updated +
+
+ 7 years ago +
+
+ + +
+
+
+ , + "container":
+
+ +
+ Updated +
+
+ 7 years ago +
+
+ + +
+
+
, + "debug": [Function], + "findAllByAltText": [Function], + "findAllByDisplayValue": [Function], + "findAllByLabelText": [Function], + "findAllByPlaceholderText": [Function], + "findAllByRole": [Function], + "findAllByTestId": [Function], + "findAllByText": [Function], + "findAllByTitle": [Function], + "findByAltText": [Function], + "findByDisplayValue": [Function], + "findByLabelText": [Function], + "findByPlaceholderText": [Function], + "findByRole": [Function], + "findByTestId": [Function], + "findByText": [Function], + "findByTitle": [Function], + "getAllByAltText": [Function], + "getAllByDisplayValue": [Function], + "getAllByLabelText": [Function], + "getAllByPlaceholderText": [Function], + "getAllByRole": [Function], + "getAllByTestId": [Function], + "getAllByText": [Function], + "getAllByTitle": [Function], + "getByAltText": [Function], + "getByDisplayValue": [Function], + "getByLabelText": [Function], + "getByPlaceholderText": [Function], + "getByRole": [Function], + "getByTestId": [Function], + "getByText": [Function], + "getByTitle": [Function], + "queryAllByAltText": [Function], + "queryAllByDisplayValue": [Function], + "queryAllByLabelText": [Function], + "queryAllByPlaceholderText": [Function], + "queryAllByRole": [Function], + "queryAllByTestId": [Function], + "queryAllByText": [Function], + "queryAllByTitle": [Function], + "queryByAltText": [Function], + "queryByDisplayValue": [Function], + "queryByLabelText": [Function], + "queryByPlaceholderText": [Function], + "queryByRole": [Function], + "queryByTestId": [Function], + "queryByText": [Function], + "queryByTitle": [Function], + "rerender": [Function], + "unmount": [Function], +} +`; diff --git a/src/typesGitHub.ts b/src/typesGitHub.ts index 39e567236..a9ebf20fc 100644 --- a/src/typesGitHub.ts +++ b/src/typesGitHub.ts @@ -33,6 +33,7 @@ export type SubjectType = | 'Issue' | 'PullRequest' | 'Release' + | 'RepositoryDependabotAlertsThread' | 'RepositoryInvitation' | 'RepositoryVulnerabilityAlert' | 'WorkflowRun'; diff --git a/src/utils/helpers.test.ts b/src/utils/helpers.test.ts index 2dd653150..49c83bfea 100644 --- a/src/utils/helpers.test.ts +++ b/src/utils/helpers.test.ts @@ -375,6 +375,25 @@ describe('utils/helpers.ts', () => { ); }); + it('Repository Dependabot Alerts Thread url', async () => { + const subject = { + title: 'Your repository has dependencies with security vulnerabilities', + url: null, + latest_comment_url: null, + type: 'RepositoryDependabotAlertsThread' as SubjectType, + }; + + const result = await generateGitHubWebUrl({ + ...mockSingleNotification, + subject: subject, + }); + + expect(apiRequestAuthMock).toHaveBeenCalledTimes(0); + expect(result).toBe( + `https://github.com/gitify-app/notifications-test/security/dependabot?${mockNotificationReferrer}`, + ); + }); + describe('Workflow Run URLs', () => { it('approval requested', async () => { const subject = { diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index cab914a54..31f047f0b 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -125,6 +125,9 @@ export async function generateGitHubWebUrl( case 'RepositoryInvitation': url.pathname += '/invitations'; break; + case 'RepositoryDependabotAlertsThread': + url.pathname += '/security/dependabot'; + break; case 'WorkflowRun': url.href = getWorkflowRunUrl(notification); break; diff --git a/src/utils/icons.test.ts b/src/utils/icons.test.ts index 9e991f512..20d9d8aa2 100644 --- a/src/utils/icons.test.ts +++ b/src/utils/icons.test.ts @@ -149,6 +149,13 @@ describe('utils/icons.ts', () => { }), ).displayName, ).toBe('TagIcon'); + expect( + getNotificationTypeIcon( + createSubjectMock({ + type: 'RepositoryDependabotAlertsThread', + }), + ).displayName, + ).toBe('AlertIcon'); expect( getNotificationTypeIcon( createSubjectMock({ diff --git a/src/utils/icons.ts b/src/utils/icons.ts index b85864e2c..f6ae990bd 100644 --- a/src/utils/icons.ts +++ b/src/utils/icons.ts @@ -84,6 +84,8 @@ export function getNotificationTypeIcon(subject: Subject): FC { } case 'Release': return TagIcon; + case 'RepositoryDependabotAlertsThread': + return AlertIcon; case 'RepositoryInvitation': return MailIcon; case 'RepositoryVulnerabilityAlert':