Skip to content

Commit d91a655

Browse files
authored
refactor: split metrics into individual components (#2582)
* refactor: split metrics into individual components Signed-off-by: Adam Setch <adam.setch@outlook.com> * refactor: split metrics into individual components Signed-off-by: Adam Setch <adam.setch@outlook.com> --------- Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent 3d4465e commit d91a655

22 files changed

Lines changed: 2636 additions & 6936 deletions
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { renderWithAppContext } from '../../__helpers__/test-utils';
2+
import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
3+
4+
import { CommentsPill } from './CommentsPill';
5+
6+
describe('renderer/components/metrics/CommentsPill.tsx', () => {
7+
it('renders with no comments (null)', () => {
8+
const mockNotification = { ...mockGitifyNotification };
9+
mockNotification.subject.commentCount = null;
10+
11+
const tree = renderWithAppContext(
12+
<CommentsPill commentCount={mockNotification.subject.commentCount} />,
13+
);
14+
15+
expect(tree).toMatchSnapshot();
16+
});
17+
18+
it('renders with 1 comment', () => {
19+
const mockNotification = { ...mockGitifyNotification };
20+
mockNotification.subject.commentCount = 1;
21+
22+
const tree = renderWithAppContext(
23+
<CommentsPill commentCount={mockNotification.subject.commentCount} />,
24+
);
25+
26+
expect(tree).toMatchSnapshot();
27+
});
28+
29+
it('renders with multiple comments', () => {
30+
const mockNotification = { ...mockGitifyNotification };
31+
mockNotification.subject.commentCount = 2;
32+
33+
const tree = renderWithAppContext(
34+
<CommentsPill commentCount={mockNotification.subject.commentCount} />,
35+
);
36+
37+
expect(tree).toMatchSnapshot();
38+
});
39+
});
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { FC } from 'react';
2+
3+
import { CommentIcon } from '@primer/octicons-react';
4+
5+
import { IconColor } from '../../types';
6+
7+
import { formatMetricDescription } from '../../utils/notifications/formatters';
8+
import { MetricPill } from './MetricPill';
9+
10+
export interface CommentsPillProps {
11+
commentCount: number;
12+
}
13+
14+
export const CommentsPill: FC<CommentsPillProps> = ({ commentCount }) => {
15+
if (!commentCount) {
16+
return null;
17+
}
18+
19+
const description = formatMetricDescription(commentCount, 'comment');
20+
21+
return (
22+
<MetricPill
23+
color={IconColor.GRAY}
24+
icon={CommentIcon}
25+
metric={commentCount}
26+
title={description}
27+
/>
28+
);
29+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { renderWithAppContext } from '../../__helpers__/test-utils';
2+
import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
3+
4+
import { LabelsPill } from './LabelsPill';
5+
6+
describe('renderer/components/metrics/LabelsPill.tsx', () => {
7+
it('renders labels pill', () => {
8+
const mockNotification = { ...mockGitifyNotification };
9+
mockNotification.subject.labels = ['enhancement', 'good-first-issue'];
10+
11+
const tree = renderWithAppContext(
12+
<LabelsPill labels={mockNotification.subject.labels} />,
13+
);
14+
15+
expect(tree).toMatchSnapshot();
16+
});
17+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { FC } from 'react';
2+
3+
import { TagIcon } from '@primer/octicons-react';
4+
5+
import { IconColor } from '../../types';
6+
7+
import { formatMetricDescription } from '../../utils/notifications/formatters';
8+
import { MetricPill } from './MetricPill';
9+
10+
export interface LabelsPillProps {
11+
labels: string[];
12+
}
13+
14+
export const LabelsPill: FC<LabelsPillProps> = ({ labels }) => {
15+
if (!labels?.length) {
16+
return null;
17+
}
18+
19+
const description = formatMetricDescription(
20+
labels.length,
21+
'label',
22+
(count, noun) => {
23+
const formatted = labels.map((label) => `🏷️ ${label}`).join(', ');
24+
25+
return `${count} ${noun}: ${formatted}`;
26+
},
27+
);
28+
29+
return (
30+
<MetricPill
31+
color={IconColor.GRAY}
32+
icon={TagIcon}
33+
metric={labels.length}
34+
title={description}
35+
/>
36+
);
37+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { renderWithAppContext } from '../../__helpers__/test-utils';
2+
import { mockGitifyNotification } from '../../__mocks__/notifications-mocks';
3+
4+
import { LinkedIssuesPill } from './LinkedIssuesPill';
5+
6+
describe('renderer/components/metrics/LinkedIssuesPill.tsx', () => {
7+
it('renders when linked to one issue/pr', () => {
8+
const mockNotification = { ...mockGitifyNotification };
9+
mockNotification.subject.linkedIssues = ['#1'];
10+
11+
const tree = renderWithAppContext(
12+
<LinkedIssuesPill linkedIssues={mockNotification.subject.linkedIssues} />,
13+
);
14+
15+
expect(tree).toMatchSnapshot();
16+
});
17+
18+
it('renders when linked to multiple issues/prs', () => {
19+
const mockNotification = { ...mockGitifyNotification };
20+
mockNotification.subject.linkedIssues = ['#1', '#2'];
21+
22+
const tree = renderWithAppContext(
23+
<LinkedIssuesPill linkedIssues={mockNotification.subject.linkedIssues} />,
24+
);
25+
26+
expect(tree).toMatchSnapshot();
27+
});
28+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { FC } from 'react';
2+
3+
import { IssueOpenedIcon } from '@primer/octicons-react';
4+
5+
import { IconColor } from '../../types';
6+
7+
import { formatMetricDescription } from '../../utils/notifications/formatters';
8+
import { MetricPill } from './MetricPill';
9+
10+
export interface LinkedIssuesPillProps {
11+
linkedIssues: string[];
12+
}
13+
14+
export const LinkedIssuesPill: FC<LinkedIssuesPillProps> = ({
15+
linkedIssues,
16+
}) => {
17+
if (!linkedIssues?.length) {
18+
return null;
19+
}
20+
21+
const description = formatMetricDescription(
22+
linkedIssues.length,
23+
'issue',
24+
(count, noun) => `Linked to ${count} ${noun}: ${linkedIssues.join(', ')}`,
25+
);
26+
27+
return (
28+
<MetricPill
29+
color={IconColor.GRAY}
30+
icon={IssueOpenedIcon}
31+
metric={linkedIssues.length}
32+
title={description}
33+
/>
34+
);
35+
};

0 commit comments

Comments
 (0)