Skip to content

Commit a2ffd6c

Browse files
authored
feat: filter by notification type (#1860)
* feat: filter by notification type Signed-off-by: Adam Setch <[email protected]> * feat: filter by notification type Signed-off-by: Adam Setch <[email protected]> * feat: filter by notification type Signed-off-by: Adam Setch <[email protected]> --------- Signed-off-by: Adam Setch <[email protected]>
1 parent adc30a5 commit a2ffd6c

File tree

14 files changed

+1861
-19
lines changed

14 files changed

+1861
-19
lines changed

src/renderer/__mocks__/state-mocks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ const mockFilters: FilterSettingsState = {
109109
filterUserTypes: [],
110110
filterIncludeHandles: [],
111111
filterExcludeHandles: [],
112+
filterSubjectTypes: [],
112113
filterStates: [],
113114
filterReasons: [],
114115
};

src/renderer/components/filters/StateFilter.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { type FC, useContext } from 'react';
22

3-
import { BellIcon } from '@primer/octicons-react';
3+
import { IssueOpenedIcon } from '@primer/octicons-react';
44
import { Stack, Text } from '@primer/react';
55

66
import { AppContext } from '../../context/App';
@@ -21,7 +21,7 @@ export const StateFilter: FC = () => {
2121
return (
2222
<fieldset id="filter-state" className="mb-3">
2323
<Stack direction="horizontal" gap="condensed" align="baseline">
24-
<Title icon={BellIcon}>State</Title>
24+
<Title icon={IssueOpenedIcon}>State</Title>
2525
<Tooltip
2626
name="tooltip-filter-state"
2727
tooltip={
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { act, fireEvent, render, screen } from '@testing-library/react';
2+
import { MemoryRouter } from 'react-router-dom';
3+
import { mockAccountNotifications } from '../../__mocks__/notifications-mocks';
4+
import { mockSettings } from '../../__mocks__/state-mocks';
5+
import { AppContext } from '../../context/App';
6+
import type { SettingsState } from '../../types';
7+
import { SubjectTypeFilter } from './SubjectTypeFilter';
8+
9+
describe('renderer/components/filters/SubjectTypeFilter.tsx', () => {
10+
const updateFilter = jest.fn();
11+
12+
it('should render itself & its children', () => {
13+
const tree = render(
14+
<AppContext.Provider
15+
value={{
16+
settings: {
17+
...mockSettings,
18+
} as SettingsState,
19+
notifications: mockAccountNotifications,
20+
}}
21+
>
22+
<MemoryRouter>
23+
<SubjectTypeFilter />
24+
</MemoryRouter>
25+
</AppContext.Provider>,
26+
);
27+
28+
expect(tree).toMatchSnapshot();
29+
});
30+
31+
it('should be able to toggle subject type - none already set', async () => {
32+
await act(async () => {
33+
render(
34+
<AppContext.Provider
35+
value={{
36+
settings: {
37+
...mockSettings,
38+
filterSubjectTypes: [],
39+
},
40+
notifications: [],
41+
updateFilter,
42+
}}
43+
>
44+
<MemoryRouter>
45+
<SubjectTypeFilter />
46+
</MemoryRouter>
47+
</AppContext.Provider>,
48+
);
49+
});
50+
51+
fireEvent.click(screen.getByLabelText('Issue'));
52+
53+
expect(updateFilter).toHaveBeenCalledWith(
54+
'filterSubjectTypes',
55+
'Issue',
56+
true,
57+
);
58+
59+
expect(
60+
screen.getByLabelText('Issue').parentNode.parentNode,
61+
).toMatchSnapshot();
62+
});
63+
64+
it('should be able to toggle subject type - some filters already set', async () => {
65+
await act(async () => {
66+
render(
67+
<AppContext.Provider
68+
value={{
69+
settings: {
70+
...mockSettings,
71+
filterSubjectTypes: ['Issue'],
72+
},
73+
notifications: [],
74+
updateFilter,
75+
}}
76+
>
77+
<MemoryRouter>
78+
<SubjectTypeFilter />
79+
</MemoryRouter>
80+
</AppContext.Provider>,
81+
);
82+
});
83+
84+
fireEvent.click(screen.getByLabelText('Pull Request'));
85+
86+
expect(updateFilter).toHaveBeenCalledWith(
87+
'filterSubjectTypes',
88+
'PullRequest',
89+
true,
90+
);
91+
92+
expect(
93+
screen.getByLabelText('Pull Request').parentNode.parentNode,
94+
).toMatchSnapshot();
95+
});
96+
});
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { type FC, useContext } from 'react';
2+
3+
import { BellIcon } from '@primer/octicons-react';
4+
import { Stack, Text } from '@primer/react';
5+
6+
import { AppContext } from '../../context/App';
7+
import type { SubjectType } from '../../typesGitHub';
8+
import {
9+
FILTERS_SUBJECT_TYPES,
10+
getSubjectTypeDetails,
11+
getSubjectTypeFilterCount,
12+
isSubjectTypeFilterSet,
13+
} from '../../utils/notifications/filters/subjectType';
14+
import { Checkbox } from '../fields/Checkbox';
15+
import { Tooltip } from '../fields/Tooltip';
16+
import { Title } from '../primitives/Title';
17+
18+
export const SubjectTypeFilter: FC = () => {
19+
const { updateFilter, settings, notifications } = useContext(AppContext);
20+
21+
return (
22+
<fieldset id="filter-subject-type" className="mb-3">
23+
<Stack direction="horizontal" gap="condensed" align="baseline">
24+
<Title icon={BellIcon}>Type</Title>
25+
<Tooltip
26+
name="tooltip-filter-subject-type"
27+
tooltip={
28+
<Stack direction="vertical" gap="condensed">
29+
<Text>Filter notifications by type.</Text>
30+
</Stack>
31+
}
32+
/>
33+
</Stack>
34+
35+
<Stack direction="vertical" gap="condensed">
36+
{Object.keys(FILTERS_SUBJECT_TYPES).map((subjectType: SubjectType) => {
37+
const subjectTypeDetails = getSubjectTypeDetails(subjectType);
38+
const subjectTypeTitle = subjectTypeDetails.title;
39+
const subjectTypeDescription = subjectTypeDetails.description;
40+
const isSubjectTypeChecked = isSubjectTypeFilterSet(
41+
settings,
42+
subjectType,
43+
);
44+
const subjectTypeCount = getSubjectTypeFilterCount(
45+
notifications,
46+
subjectType,
47+
);
48+
49+
return (
50+
<Checkbox
51+
key={subjectType}
52+
name={subjectTypeTitle}
53+
label={subjectTypeTitle}
54+
checked={isSubjectTypeChecked}
55+
onChange={(evt) =>
56+
updateFilter(
57+
'filterSubjectTypes',
58+
subjectType,
59+
evt.target.checked,
60+
)
61+
}
62+
tooltip={
63+
subjectTypeDescription ? (
64+
<Text>{subjectTypeDescription}</Text>
65+
) : null
66+
}
67+
disabled={!settings.detailedNotifications}
68+
counter={subjectTypeCount}
69+
/>
70+
);
71+
})}
72+
</Stack>
73+
</fieldset>
74+
);
75+
};

src/renderer/components/filters/__snapshots__/StateFilter.test.tsx.snap

Lines changed: 20 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)