Skip to content

Commit 150f3ee

Browse files
committed
feat: display toasts
1 parent 4e17279 commit 150f3ee

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

electron/renderer/components/layout.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { EuiPageTemplate } from '@elastic/eui';
22
import type { ReactNode } from 'react';
33
import { Sidebar } from './sidebar/sidebar.jsx';
4+
import { ToastList } from './toast/toast-list.jsx';
45

56
export interface LayoutProps {
67
/**
@@ -34,6 +35,7 @@ export const Layout: React.FC<LayoutProps> = (
3435
</EuiPageTemplate.Sidebar>
3536
<EuiPageTemplate.Section paddingSize="none" grow={true}>
3637
{children}
38+
<ToastList />
3739
</EuiPageTemplate.Section>
3840
</EuiPageTemplate>
3941
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { EuiGlobalToastList } from '@elastic/eui';
2+
import type { EuiIconType } from '@elastic/eui/src/components/icon/icon';
3+
import type { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
4+
import type { ReactNode } from 'react';
5+
import { useState } from 'react';
6+
import { v4 as uuid } from 'uuid';
7+
import { useLogger } from '../../hooks/logger.jsx';
8+
import { useSubscribe } from '../../hooks/pubsub.jsx';
9+
10+
export interface ToastListProps {
11+
/**
12+
* How long the toast should be displayed in milliseconds.
13+
* Default is 5000ms.
14+
*/
15+
toastLifeTimeMs?: number;
16+
}
17+
18+
export interface ToastAddProps {
19+
title: string;
20+
text?: ReactNode;
21+
type?: 'success' | 'warning' | 'danger' | 'info';
22+
}
23+
24+
export const ToastList: React.FC<ToastListProps> = (
25+
props: ToastListProps
26+
): ReactNode => {
27+
const { toastLifeTimeMs = 5000 } = props;
28+
29+
const logger = useLogger('cmp:toast-list');
30+
31+
const [toasts, setToasts] = useState<Array<Toast>>([]);
32+
33+
useSubscribe(['toast:add'], (toastAddProps: ToastAddProps) => {
34+
const { title, text, type } = toastAddProps;
35+
36+
let iconType: EuiIconType | undefined;
37+
let color: Toast['color'] | undefined;
38+
39+
switch (type) {
40+
case 'success':
41+
iconType = 'check';
42+
color = 'success';
43+
break;
44+
case 'warning':
45+
iconType = 'warning';
46+
color = 'warning';
47+
break;
48+
case 'danger':
49+
iconType = 'error';
50+
color = 'danger';
51+
break;
52+
case 'info':
53+
// iconType = 'iInCircle';
54+
color = 'primary';
55+
break;
56+
}
57+
58+
const toast: Toast = {
59+
id: uuid(),
60+
title,
61+
text,
62+
iconType,
63+
color,
64+
};
65+
66+
logger.debug('add toast', {
67+
toast,
68+
});
69+
70+
setToasts((prevToasts) => {
71+
return [...prevToasts, toast];
72+
});
73+
});
74+
75+
// Callback to actually remove the toast from the list.
76+
const onDismissToast = (toastToRemove: Toast) => {
77+
logger.debug('dismiss toast', {
78+
toast: toastToRemove,
79+
});
80+
81+
setToasts((prevToasts) => {
82+
return prevToasts.filter((toast) => {
83+
return toast.id !== toastToRemove.id;
84+
});
85+
});
86+
};
87+
88+
// Callback to notify that the user has cleared all toasts.
89+
// For each toast that was cleared, `onDismissToast` was called already.
90+
// Nothing to actually do here, just log it.
91+
const onClearAllToasts = () => {
92+
logger.debug('clear all toasts');
93+
};
94+
95+
return (
96+
<EuiGlobalToastList
97+
toasts={toasts}
98+
toastLifeTimeMs={toastLifeTimeMs}
99+
dismissToast={onDismissToast}
100+
onClearAllToasts={onClearAllToasts}
101+
/>
102+
);
103+
};
104+
105+
ToastList.displayName = 'ToastList';

0 commit comments

Comments
 (0)