diff --git a/src/renderer/utils/notifications/filters/filter.ts b/src/renderer/utils/notifications/filters/filter.ts index 69c412608..6f2e3c0db 100644 --- a/src/renderer/utils/notifications/filters/filter.ts +++ b/src/renderer/utils/notifications/filters/filter.ts @@ -1,5 +1,9 @@ import type { SettingsState } from '../../../types'; -import type { Notification } from '../../../typesGitHub'; +import type { + Notification, + StateType, + SubjectUser, +} from '../../../typesGitHub'; import { filterNotificationByHandle, hasExcludeHandleFilters, @@ -45,37 +49,11 @@ export function filterDetailedNotifications( let passesFilters = true; if (settings.detailedNotifications) { - if (userTypeFilter.hasFilters(settings)) { - passesFilters = - passesFilters && - settings.filterUserTypes.some((userType) => - userTypeFilter.filterNotification(notification, userType), - ); - } - - if (hasIncludeHandleFilters(settings)) { - passesFilters = - passesFilters && - settings.filterIncludeHandles.some((handle) => - filterNotificationByHandle(notification, handle), - ); - } - - if (hasExcludeHandleFilters(settings)) { - passesFilters = - passesFilters && - !settings.filterExcludeHandles.some((handle) => - filterNotificationByHandle(notification, handle), - ); - } - - if (stateFilter.hasFilters(settings)) { - passesFilters = - passesFilters && - settings.filterStates.some((state) => - stateFilter.filterNotification(notification, state), - ); - } + passesFilters = + passesFilters && passesUserFilters(notification, settings); + + passesFilters = + passesFilters && passesStateFilter(notification, settings); } return passesFilters; @@ -92,3 +70,67 @@ export function hasAnyFiltersSet(settings: SettingsState): boolean { reasonFilter.hasFilters(settings) ); } + +function passesUserFilters( + notification: Notification, + settings: SettingsState, +): boolean { + let passesFilters = true; + + if (userTypeFilter.hasFilters(settings)) { + passesFilters = + passesFilters && + settings.filterUserTypes.some((userType) => + userTypeFilter.filterNotification(notification, userType), + ); + } + + if (hasIncludeHandleFilters(settings)) { + passesFilters = + passesFilters && + settings.filterIncludeHandles.some((handle) => + filterNotificationByHandle(notification, handle), + ); + } + + if (hasExcludeHandleFilters(settings)) { + passesFilters = + passesFilters && + !settings.filterExcludeHandles.some((handle) => + filterNotificationByHandle(notification, handle), + ); + } + + return passesFilters; +} + +function passesStateFilter( + notification: Notification, + settings: SettingsState, +): boolean { + if (stateFilter.hasFilters(settings)) { + return settings.filterStates.some((state) => + stateFilter.filterNotification(notification, state), + ); + } + + return true; +} + +export function isStateFilteredOut( + state: StateType, + settings: SettingsState, +): boolean { + const notification = { subject: { state: state } } as Notification; + + return !passesStateFilter(notification, settings); +} + +export function isUserFilteredOut( + user: SubjectUser, + settings: SettingsState, +): boolean { + const notification = { subject: { user: user } } as Notification; + + return !passesUserFilters(notification, settings); +} diff --git a/src/renderer/utils/notifications/notifications.ts b/src/renderer/utils/notifications/notifications.ts index d1ccf44a0..8c0473234 100644 --- a/src/renderer/utils/notifications/notifications.ts +++ b/src/renderer/utils/notifications/notifications.ts @@ -108,7 +108,10 @@ export async function enrichNotifications( let additionalSubjectDetails: GitifySubject = {}; try { - additionalSubjectDetails = await getGitifySubjectDetails(notification); + additionalSubjectDetails = await getGitifySubjectDetails( + notification, + settings, + ); } catch (err) { logError( 'enrichNotifications', diff --git a/src/renderer/utils/subject.test.ts b/src/renderer/utils/subject.test.ts index 7b9ed2596..ce0d7ff8e 100644 --- a/src/renderer/utils/subject.test.ts +++ b/src/renderer/utils/subject.test.ts @@ -33,6 +33,7 @@ const mockDiscussionAuthor: DiscussionAuthor = { }; import * as logger from '../../shared/logger'; +import { mockSettings } from '../__mocks__/state-mocks'; describe('renderer/utils/subject.ts', () => { beforeEach(() => { @@ -49,7 +50,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'cancelled', @@ -63,7 +67,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'failure', @@ -77,7 +84,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'failure', @@ -91,7 +101,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'failure', @@ -105,7 +118,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'skipped', @@ -119,7 +135,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'success', @@ -133,7 +152,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toBeNull(); }); @@ -144,7 +166,10 @@ describe('renderer/utils/subject.ts', () => { type: 'CheckSuite', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toBeNull(); }); @@ -169,7 +194,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/comments/141012658') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: null, @@ -196,7 +224,10 @@ describe('renderer/utils/subject.ts', () => { ) .reply(200, { author: mockAuthor }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: null, @@ -208,6 +239,22 @@ describe('renderer/utils/subject.ts', () => { }, }); }); + + it('return early if commit state filtered', async () => { + const mockNotification = partialMockNotification({ + title: 'This is a commit with comments', + type: 'Commit', + url: 'https://api.github.com/repos/gitify-app/notifications-test/commits/d2a86d80e3d24ea9510d5de6c147e53c30f313a8' as Link, + latest_comment_url: null, + }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterStates: ['closed'], + }); + + expect(result).toEqual(null); + }); }); describe('Discussions', () => { @@ -235,7 +282,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -262,7 +312,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -289,7 +342,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -316,7 +372,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -343,7 +402,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -370,7 +432,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -405,7 +470,10 @@ describe('renderer/utils/subject.ts', () => { }, }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -420,6 +488,25 @@ describe('renderer/utils/subject.ts', () => { labels: ['enhancement'], }); }); + + it('early return if discussion state filtered', async () => { + nock('https://api.github.com/') + .post('/graphql') + .reply(200, { + data: { + search: { + nodes: [mockDiscussionNode(null, false)], + }, + }, + }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterStates: ['closed'], + }); + + expect(result).toEqual(null); + }); }); describe('Issues', () => { @@ -449,7 +536,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/comments/302888448') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -478,7 +568,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/comments/302888448') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -508,7 +601,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/comments/302888448') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -538,7 +634,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/comments/302888448') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -568,7 +667,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/comments/302888448') .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -597,7 +699,10 @@ describe('renderer/utils/subject.ts', () => { labels: [], }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -629,7 +734,10 @@ describe('renderer/utils/subject.ts', () => { ) .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -660,7 +768,10 @@ describe('renderer/utils/subject.ts', () => { ) .reply(200, { user: mockCommenter }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -675,6 +786,24 @@ describe('renderer/utils/subject.ts', () => { }); }); }); + + it('early return if issue state filtered out', async () => { + nock('https://api.github.com/') + .get('/repos/gitify-app/notifications-test/issues/1') + .reply(200, { + number: 123, + state: 'open', + user: mockAuthor, + labels: [], + }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterStates: ['closed'], + }); + + expect(result).toEqual(null); + }); }); describe('Pull Requests', () => { @@ -710,7 +839,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -747,7 +879,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -784,7 +919,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -821,7 +959,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -857,7 +998,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -892,7 +1036,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -990,7 +1137,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -1029,7 +1179,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/pulls/1/reviews') .reply(200, []); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ number: 123, @@ -1082,6 +1235,50 @@ describe('renderer/utils/subject.ts', () => { expect(result).toEqual(['#1', '#2', '#3']); }); }); + + it('early return if pull request state filtered', async () => { + nock('https://api.github.com/') + .get('/repos/gitify-app/notifications-test/pulls/1') + .reply(200, { + number: 123, + state: 'open', + draft: false, + merged: false, + user: mockAuthor, + labels: [], + }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterStates: ['closed'], + }); + + expect(result).toEqual(null); + }); + + it('early return if pull request user filtered', async () => { + nock('https://api.github.com/') + .get('/repos/gitify-app/notifications-test/pulls/1') + .reply(200, { + number: 123, + state: 'open', + draft: false, + merged: false, + user: mockAuthor, + labels: [], + }); + + nock('https://api.github.com/') + .get('/repos/gitify-app/notifications-test/issues/comments/302888448') + .reply(200, { user: mockCommenter }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterUserTypes: ['Bot'], + }); + + expect(result).toEqual(null); + }); }); describe('Releases', () => { @@ -1098,7 +1295,10 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/releases/1') .reply(200, { author: mockAuthor }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: null, @@ -1110,6 +1310,23 @@ describe('renderer/utils/subject.ts', () => { }, }); }); + + it('return early if release state filtered', async () => { + const mockNotification = partialMockNotification({ + title: 'This is a mock release', + type: 'Release', + url: 'https://api.github.com/repos/gitify-app/notifications-test/releases/1' as Link, + latest_comment_url: + 'https://api.github.com/repos/gitify-app/notifications-test/releases/1' as Link, + }); + + const result = await getGitifySubjectDetails(mockNotification, { + ...mockSettings, + filterStates: ['closed'], + }); + + expect(result).toEqual(null); + }); }); describe('WorkflowRuns - GitHub Actions', () => { @@ -1119,7 +1336,10 @@ describe('renderer/utils/subject.ts', () => { type: 'WorkflowRun', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toEqual({ state: 'waiting', @@ -1134,7 +1354,10 @@ describe('renderer/utils/subject.ts', () => { type: 'WorkflowRun', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toBeNull(); }); @@ -1145,7 +1368,10 @@ describe('renderer/utils/subject.ts', () => { type: 'WorkflowRun', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toBeNull(); }); @@ -1159,7 +1385,10 @@ describe('renderer/utils/subject.ts', () => { type: 'RepositoryInvitation', }); - const result = await getGitifySubjectDetails(mockNotification); + const result = await getGitifySubjectDetails( + mockNotification, + mockSettings, + ); expect(result).toBeNull(); }); @@ -1184,7 +1413,7 @@ describe('renderer/utils/subject.ts', () => { .get('/repos/gitify-app/notifications-test/issues/1') .replyWithError(mockError); - await getGitifySubjectDetails(mockNotification); + await getGitifySubjectDetails(mockNotification, mockSettings); expect(logErrorSpy).toHaveBeenCalledWith( 'getGitifySubjectDetails', diff --git a/src/renderer/utils/subject.ts b/src/renderer/utils/subject.ts index def607af1..dcb1e6065 100644 --- a/src/renderer/utils/subject.ts +++ b/src/renderer/utils/subject.ts @@ -1,7 +1,7 @@ import { differenceInMilliseconds } from 'date-fns'; import { logError } from '../../shared/logger'; -import type { Link } from '../types'; +import type { Link, SettingsState } from '../types'; import type { CheckSuiteAttributes, CheckSuiteStatus, @@ -13,6 +13,7 @@ import type { PullRequest, PullRequestReview, PullRequestStateType, + StateType, SubjectUser, User, WorkflowRunAttributes, @@ -27,24 +28,29 @@ import { getPullRequestReviews, getRelease, } from './api/client'; +import { + isStateFilteredOut, + isUserFilteredOut, +} from './notifications/filters/filter'; export async function getGitifySubjectDetails( notification: Notification, + settings: SettingsState, ): Promise { try { switch (notification.subject.type) { case 'CheckSuite': return getGitifySubjectForCheckSuite(notification); case 'Commit': - return getGitifySubjectForCommit(notification); + return getGitifySubjectForCommit(notification, settings); case 'Discussion': - return await getGitifySubjectForDiscussion(notification); + return await getGitifySubjectForDiscussion(notification, settings); case 'Issue': - return await getGitifySubjectForIssue(notification); + return await getGitifySubjectForIssue(notification, settings); case 'PullRequest': - return await getGitifySubjectForPullRequest(notification); + return await getGitifySubjectForPullRequest(notification, settings); case 'Release': - return await getGitifySubjectForRelease(notification); + return await getGitifySubjectForRelease(notification, settings); case 'WorkflowRun': return getGitifySubjectForWorkflowRun(notification); default: @@ -122,8 +128,15 @@ function getGitifySubjectForCheckSuite( async function getGitifySubjectForCommit( notification: Notification, + settings: SettingsState, ): Promise { let user: User; + const commitState: StateType = null; // Commit notifications are stateless + + // Return early if this notification would be hidden by filters + if (isStateFilteredOut(commitState, settings)) { + return null; + } if (notification.subject.latest_comment_url) { const commitComment = ( @@ -143,13 +156,14 @@ async function getGitifySubjectForCommit( } return { - state: null, + state: commitState, user: getSubjectUser([user]), }; } async function getGitifySubjectForDiscussion( notification: Notification, + settings: SettingsState, ): Promise { const discussion = await getLatestDiscussion(notification); let discussionState: DiscussionStateType = 'OPEN'; @@ -164,6 +178,16 @@ async function getGitifySubjectForDiscussion( } } + // Return early if this notification would be hidden by filters + if (isStateFilteredOut(discussionState, settings)) { + return null; + } + + // Return early if this notification would be hidden by filters + if (isStateFilteredOut(discussionState, settings)) { + return null; + } + const latestDiscussionComment = getClosestDiscussionCommentOrReply( notification, discussion.comments.nodes, @@ -224,11 +248,19 @@ export function getClosestDiscussionCommentOrReply( async function getGitifySubjectForIssue( notification: Notification, + settings: SettingsState, ): Promise { const issue = ( await getIssue(notification.subject.url, notification.account.token) ).data; + const issueState = issue.state_reason ?? issue.state; + + // Return early if this notification would be hidden by filters + if (isStateFilteredOut(issueState, settings)) { + return null; + } + let issueCommentUser: User; if (notification.subject.latest_comment_url) { @@ -253,6 +285,7 @@ async function getGitifySubjectForIssue( async function getGitifySubjectForPullRequest( notification: Notification, + settings: SettingsState, ): Promise { const pr = ( await getPullRequest(notification.subject.url, notification.account.token) @@ -265,8 +298,12 @@ async function getGitifySubjectForPullRequest( prState = 'draft'; } - let prCommentUser: User; + // Return early if this notification would be hidden by state filters + if (isStateFilteredOut(prState, settings)) { + return null; + } + let prCommentUser: User; if ( notification.subject.latest_comment_url && notification.subject.latest_comment_url !== notification.subject.url @@ -280,13 +317,20 @@ async function getGitifySubjectForPullRequest( prCommentUser = prComment.user; } + const prUser = getSubjectUser([prCommentUser, pr.user]); + + // Return early if this notification would be hidden by user filters + if (isUserFilteredOut(prUser, settings)) { + return null; + } + const reviews = await getLatestReviewForReviewers(notification); const linkedIssues = parseLinkedIssuesFromPr(pr); return { number: pr.number, state: prState, - user: getSubjectUser([prCommentUser, pr.user]), + user: prUser, reviews: reviews, comments: pr.comments, labels: pr.labels?.map((label) => label.name) ?? [], @@ -368,13 +412,21 @@ export function parseLinkedIssuesFromPr(pr: PullRequest): string[] { async function getGitifySubjectForRelease( notification: Notification, + settings: SettingsState, ): Promise { + const releaseState: StateType = null; // Release notifications are stateless + + // Return early if this notification would be hidden by filters + if (isStateFilteredOut(releaseState, settings)) { + return null; + } + const release = ( await getRelease(notification.subject.url, notification.account.token) ).data; return { - state: null, + state: releaseState, user: getSubjectUser([release.author]), }; }