Skip to content

Commit 90899d0

Browse files
authored
Merge pull request #6670 from WiXSL/add-multiline-notifications
Add `Notification` component `multiLine` prop
2 parents d84013a + 75441e2 commit 90899d0

File tree

7 files changed

+92
-13
lines changed

7 files changed

+92
-13
lines changed

docs/Actions.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -641,12 +641,13 @@ const NotifyButton = () => {
641641
};
642642
```
643643

644-
The callback takes 5 arguments:
645-
- the message to display
646-
- the level of the notification (`info`, `success` or `warning` - the default is `info`)
647-
- an `options` object to pass to the `translate` function (because notification messages are translated if your admin has an `i18nProvider`). It is useful for inserting variables into the translation.
648-
- an `undoable` boolean. Set it to `true` if the notification should contain an "undo" button
649-
- a `duration` number. Set it to `0` if the notification should not be dismissible.
644+
The callback takes 6 arguments:
645+
- The message to display
646+
- The level of the notification (`info`, `success` or `warning` - the default is `info`)
647+
- An `options` object to pass to the `translate` function (because notification messages are translated if your admin has an `i18nProvider`). It is useful for inserting variables into the translation.
648+
- An `undoable` boolean. Set it to `true` if the notification should contain an "undo" button
649+
- A `duration` number. Set it to `0` if the notification should not be dismissible.
650+
- A `multiLine` boolean. Set it to `true` if the notification message should be shown in more than one line.
650651

651652
Here are more examples of `useNotify` calls:
652653

packages/ra-core/src/actions/notificationActions.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ export const SHOW_NOTIFICATION = 'RA/SHOW_NOTIFICATION';
22

33
export type NotificationType = 'success' | 'info' | 'warning' | 'error';
44

5-
interface NotificationOptions {
5+
export interface NotificationOptions {
66
// The duration in milliseconds the notification is shown
77
autoHideDuration?: number;
88
// Arguments used to translate the message
99
messageArgs?: any;
10+
// If true, the notification shows the message in multiple lines
11+
multiLine?: boolean;
1012
// If true, the notification shows an Undo button
1113
undoable?: boolean;
1214
}

packages/ra-core/src/reducer/admin/notifications.spec.ts

+12
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ describe('notifications reducer', () => {
2424
})
2525
);
2626
});
27+
it('should set multiLine when passed in payload', () => {
28+
expect([{ message: 'test', type: 'info', multiLine: true }]).toEqual(
29+
reducer(undefined, {
30+
type: SHOW_NOTIFICATION,
31+
payload: {
32+
message: 'test',
33+
type: 'info',
34+
multiLine: true,
35+
},
36+
})
37+
);
38+
});
2739
it('should set text and type upon SHOW_NOTIFICATION', () => {
2840
expect([{ message: 'foo', type: 'warning' }]).toEqual(
2941
reducer(undefined, {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import * as React from 'react';
2+
import { useEffect } from 'react';
3+
import { renderWithRedux } from 'ra-test';
4+
import { useNotify } from './index';
5+
6+
const Notification = ({
7+
type,
8+
message,
9+
undoable = false,
10+
autoHideDuration = 4000,
11+
multiLine = true,
12+
shortSignature = false,
13+
}) => {
14+
const notify = useNotify();
15+
useEffect(() => {
16+
if (shortSignature) {
17+
// @ts-ignore
18+
notify(message, {
19+
type,
20+
undoable,
21+
autoHideDuration,
22+
multiLine,
23+
});
24+
} else {
25+
notify(message, type, {}, undoable, autoHideDuration, multiLine);
26+
}
27+
}, [
28+
message,
29+
undoable,
30+
autoHideDuration,
31+
multiLine,
32+
shortSignature,
33+
type,
34+
notify,
35+
]);
36+
return null;
37+
};
38+
39+
describe('useNotify', () => {
40+
it('should show a multiline notification message', () => {
41+
const { dispatch } = renderWithRedux(
42+
<Notification
43+
type="info"
44+
message={`One Line\nTwo Lines\nThree Lines`}
45+
multiLine
46+
/>
47+
);
48+
49+
expect(dispatch).toHaveBeenCalledTimes(1);
50+
});
51+
});

packages/ra-core/src/sideEffect/useNotify.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ const useNotify = () => {
2828
type: NotificationType = 'info',
2929
messageArgs: any = {},
3030
undoable: boolean = false,
31-
autoHideDuration?: number
31+
autoHideDuration?: number,
32+
multiLine?: boolean
3233
) => {
3334
dispatch(
3435
showNotification(message, type, {
3536
messageArgs,
3637
undoable,
3738
autoHideDuration,
39+
multiLine,
3840
})
3941
);
4042
},

packages/ra-ui-materialui/src/layout/Notification.tsx

+14-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ import {
1616
useTranslate,
1717
} from 'ra-core';
1818

19-
interface Props {
19+
export interface NotificationProps extends Omit<SnackbarProps, 'open'> {
2020
type?: string;
21+
autoHideDuration?: number;
22+
multiLine?: boolean;
2123
}
2224

2325
const useStyles = makeStyles(
@@ -34,22 +36,26 @@ const useStyles = makeStyles(
3436
backgroundColor: theme.palette.error.light,
3537
color: theme.palette.error.contrastText,
3638
},
37-
undo: (props: Props & Omit<SnackbarProps, 'open'>) => ({
39+
undo: (props: NotificationProps) => ({
3840
color:
3941
props.type === 'success'
4042
? theme.palette.success.contrastText
4143
: theme.palette.primary.light,
4244
}),
45+
multiLine: {
46+
whiteSpace: 'pre-wrap',
47+
},
4348
}),
4449
{ name: 'RaNotification' }
4550
);
4651

47-
const Notification = (props: Props & Omit<SnackbarProps, 'open'>) => {
52+
const Notification = (props: NotificationProps) => {
4853
const {
4954
classes: classesOverride,
5055
type,
5156
className,
5257
autoHideDuration,
58+
multiLine,
5359
...rest
5460
} = props;
5561
const [open, setOpen] = useState(false);
@@ -97,7 +103,8 @@ const Notification = (props: Props & Omit<SnackbarProps, 'open'>) => {
97103
ContentProps={{
98104
className: classnames(
99105
styles[(notification && notification.type) || type],
100-
className
106+
className,
107+
{ [styles['multiLine']]: multiLine }
101108
),
102109
}}
103110
action={
@@ -119,11 +126,14 @@ const Notification = (props: Props & Omit<SnackbarProps, 'open'>) => {
119126

120127
Notification.propTypes = {
121128
type: PropTypes.string,
129+
autoHideDuration: PropTypes.number,
130+
multiLine: PropTypes.bool,
122131
};
123132

124133
Notification.defaultProps = {
125134
type: 'info',
126135
autoHideDuration: 4000,
136+
multiLine: false,
127137
};
128138

129139
export default Notification;

packages/ra-ui-materialui/src/layout/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import LoadingIndicator from './LoadingIndicator';
1414
import Menu, { MenuProps } from './Menu';
1515
import MenuItemLink, { MenuItemLinkProps } from './MenuItemLink';
1616
import NotFound from './NotFound';
17-
import Notification from './Notification';
17+
import Notification, { NotificationProps } from './Notification';
1818
import Responsive, { ResponsiveProps } from './Responsive';
1919
import Sidebar, { SidebarProps } from './Sidebar';
2020
import Title, { TitleProps, TitlePropType } from './Title';
@@ -41,6 +41,7 @@ export {
4141
MenuItemLink,
4242
NotFound,
4343
Notification,
44+
NotificationProps,
4445
Responsive,
4546
Sidebar,
4647
Title,

0 commit comments

Comments
 (0)