Skip to content

Commit fae3efb

Browse files
committed
feat(error): action buttons
Signed-off-by: Adam Setch <adam.setch@outlook.com>
1 parent 67785d6 commit fae3efb

7 files changed

Lines changed: 86 additions & 501 deletions

File tree

src/renderer/components/Oops.test.tsx

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { act } from '@testing-library/react';
1+
import { act, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
3+
4+
import { PersonIcon } from '@primer/octicons-react';
25

36
import {
47
ensureStableEmojis,
@@ -7,6 +10,12 @@ import {
710

811
import { Oops } from './Oops';
912

13+
const navigateMock = vi.fn();
14+
vi.mock('react-router-dom', async () => ({
15+
...(await vi.importActual('react-router-dom')),
16+
useNavigate: () => navigateMock,
17+
}));
18+
1019
describe('renderer/components/Oops.tsx', () => {
1120
beforeEach(() => {
1221
ensureStableEmojis();
@@ -37,4 +46,26 @@ describe('renderer/components/Oops.tsx', () => {
3746

3847
expect(tree.container).toMatchSnapshot();
3948
});
49+
50+
it('should render action buttons and navigate on click', async () => {
51+
const mockError = {
52+
title: 'Error title',
53+
descriptions: ['Error description'],
54+
emojis: ['🔥'],
55+
actions: [
56+
{
57+
label: 'Go somewhere',
58+
route: '/somewhere',
59+
variant: 'danger' as const,
60+
icon: PersonIcon,
61+
},
62+
],
63+
};
64+
65+
renderWithAppContext(<Oops error={mockError} />);
66+
67+
await userEvent.click(screen.getByText('Go somewhere'));
68+
69+
expect(navigateMock).toHaveBeenCalledWith('/somewhere');
70+
});
4071
});

src/renderer/components/Oops.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { type FC, useMemo } from 'react';
2+
import { useNavigate } from 'react-router-dom';
3+
4+
import { Button } from '@primer/react';
25

36
import { EmojiSplash } from './layout/EmojiSplash';
47

@@ -16,14 +19,29 @@ export const Oops: FC<OopsProps> = ({
1619
fullHeight = true,
1720
}: OopsProps) => {
1821
const err = error ?? Errors.UNKNOWN;
22+
const navigate = useNavigate();
1923

2024
const emoji = useMemo(
2125
() => err.emojis[Math.floor(Math.random() * err.emojis.length)],
2226
[err],
2327
);
2428

29+
const actions = err.actions?.length
30+
? err.actions.map((action) => (
31+
<Button
32+
key={action.route}
33+
leadingVisual={action.icon}
34+
onClick={() => navigate(action.route)}
35+
variant={action.variant}
36+
>
37+
{action.label}
38+
</Button>
39+
))
40+
: null;
41+
2542
return (
2643
<EmojiSplash
44+
actions={actions}
2745
emoji={emoji}
2846
fullHeight={fullHeight}
2947
heading={err.title}

src/renderer/components/layout/EmojiSplash.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FC } from 'react';
1+
import type { FC, ReactNode } from 'react';
22

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

@@ -11,15 +11,12 @@ interface EmojiSplashProps {
1111
heading: string;
1212
subHeadings?: string[];
1313
fullHeight?: boolean;
14+
actions?: ReactNode;
1415
}
1516

16-
export const EmojiSplash: FC<EmojiSplashProps> = ({
17-
fullHeight = true,
18-
subHeadings = [],
19-
...props
20-
}: EmojiSplashProps) => {
17+
export const EmojiSplash: FC<EmojiSplashProps> = (props: EmojiSplashProps) => {
2118
return (
22-
<Centered fullHeight={fullHeight}>
19+
<Centered fullHeight={props.fullHeight}>
2320
<Stack
2421
align="center"
2522
direction="vertical"
@@ -31,14 +28,16 @@ export const EmojiSplash: FC<EmojiSplashProps> = ({
3128
<div className="text-xl font-semibold">{props.heading}</div>
3229
</Stack>
3330

34-
{subHeadings.map((description, i) => {
31+
{props.subHeadings?.map((description, i) => {
3532
const key = `error_description_${i}`;
3633
return (
3734
<div className="text-center" key={key}>
3835
{description}
3936
</div>
4037
);
4138
})}
39+
40+
{props.actions && <div className="mt-2">{props.actions}</div>}
4241
</Stack>
4342
</Centered>
4443
);

src/renderer/components/layout/__snapshots__/EmojiSplash.test.tsx.snap

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

0 commit comments

Comments
 (0)