From 81dd1e01c6b2d1e69156192535643f27922120ee Mon Sep 17 00:00:00 2001 From: asvarcas Date: Wed, 13 Oct 2021 12:26:29 -0300 Subject: [PATCH 1/7] Add second signature to notifications --- UPGRADE.md | 7 ++--- docs/Actions.md | 23 +++++++++++----- docs/CreateEdit.md | 15 ++++++----- docs/List.md | 2 +- .../ra-core/src/sideEffect/useNotify.spec.tsx | 16 ++++++++++-- packages/ra-core/src/sideEffect/useNotify.ts | 26 ++++++++++++------- 6 files changed, 60 insertions(+), 29 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 454d0468bb0..25ca446afdb 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -118,12 +118,11 @@ Here's how to migrate the *Altering the Form Values before Submitting* example f import * as React from 'react'; import { useCallback } from 'react'; import { useForm } from 'react-final-form'; -import { SaveButton, Toolbar, useCreate, useRedirect, useNotify } from 'react-admin'; +import { SaveButton, Toolbar, useCreate, useRedirect } from 'react-admin'; const SaveWithNoteButton = ({ handleSubmit, handleSubmitWithRedirect, ...props }) => { const [create] = useCreate('posts'); const redirectTo = useRedirect(); - const notify = useNotify(); const { basePath, redirect } = props; const form = useForm(); @@ -171,9 +170,7 @@ const SaveWithNoteButton = props => { }, { onSuccess: ({ data: newRecord }) => { - notify('ra.notification.created', 'info', { - smart_count: 1, - }); + notify('ra.notification.created', { messageArgs: { smart_count: 1 } }); redirectTo(redirect, basePath, newRecord.id, newRecord); }, } diff --git a/docs/Actions.md b/docs/Actions.md index 9e77adb8315..ca468a5ff01 100644 --- a/docs/Actions.md +++ b/docs/Actions.md @@ -651,7 +651,7 @@ The callback takes 6 arguments: Here are more examples of `useNotify` calls: -```jsx +```js // notify a warning notify(`This is a warning`, 'warning'); // pass translation arguments @@ -660,6 +660,17 @@ notify('item.created', 'info', { resource: 'post' }); notify('Element updated', 'info', undefined, true); ``` +**Tip**: The callback also allows a signature with only 2 arguments, the message to display and an object with the rest of the arguments + +```js +// notify an undoable success message, with translation arguments +notify('Element deleted', { + type: 'success', + undoable: true, + messageArgs: { resource: 'post' } +}); +``` + **Tip**: When using `useNotify` as a side effect for an `undoable` Edit form, you MUST set the fourth argument to `true`, otherwise the "undo" button will not appear, and the actual update will never occur. ```jsx @@ -670,7 +681,7 @@ const PostEdit = props => { const notify = useNotify(); const onSuccess = () => { - notify(`Changes saved`, undefined, undefined, true); + notify('Changes saved`', { undoable: true }); }; return ( @@ -842,7 +853,7 @@ const ApproveButton = ({ record }) => { + onSuccess: () => { redirect('/comments'); - notify('Comment approved'); -+ notify('Comment approved', 'info', {}, true); ++ notify('Comment approved', { undoable: true }); }, onFailure: (error) => notify(`Error: ${error.message}`, 'warning'), } @@ -871,7 +882,7 @@ const ApproveButton = ({ record }) => { mutationMode: 'undoable', onSuccess: () => { redirect('/comments'); - notify('Comment approved', 'info', {}, true); + notify('Comment approved', { undoable: true }); }, onFailure: (error) => notify(`Error: ${error.message}`, 'warning'), } @@ -906,7 +917,7 @@ const ApproveButton = ({ record }) => { mutationMode: 'undoable', onSuccess: ({ data }) => { redirect('/comments'); - notify('Comment approved', 'info', {}, true); + notify('Comment approved', { undoable: true }); }, onFailure: (error) => notify(`Error: ${error.message}`, 'warning'), } @@ -988,7 +999,7 @@ const ApproveButton = ({ record }) => { const options = { mutationMode: 'undoable', onSuccess: ({ data }) => { - notify('Comment approved', 'info', {}, true); + notify('Comment approved', { undoable: true }); redirect('/comments'); }, onFailure: (error) => notify(`Error: ${error.message}`, 'warning'), diff --git a/docs/CreateEdit.md b/docs/CreateEdit.md index f5161acec2f..e7e4383535e 100644 --- a/docs/CreateEdit.md +++ b/docs/CreateEdit.md @@ -401,7 +401,7 @@ const PostEdit = props => { const redirect = useRedirect(); const onSuccess = () => { - notify(`Changes saved`) + notify(`Changes saved`); redirect('/posts'); refresh(); }; @@ -423,13 +423,16 @@ The default `onSuccess` function is: ```jsx // for the component: () => { - notify('ra.notification.created', 'info', { smart_count: 1 }); + notify('ra.notification.created', { messageArgs: { smart_count: 1 } }); redirect('edit', basePath, data.id, data); } // for the component: () => { - notify('ra.notification.updated', 'info', { smart_count: 1 }, mutationMode === 'undoable'); + notify('ra.notification.created', { + messageArgs: { smart_count: 1 }, + undoable: mutationMode === 'undoable' + }); redirect('list', basePath, data.id, data); } ``` @@ -448,7 +451,7 @@ const PostEdit = props => { const redirect = useRedirect(); const onSuccess = ({ data }) => { - notify(`Changes to post "${data.title}" saved`) + notify(`Changes to post "${data.title}" saved`); redirect('/posts'); refresh(); }; @@ -483,7 +486,7 @@ const PostEdit = props => { const redirect = useRedirect(); const onFailure = (error) => { - notify(`Could not edit post: ${error.message}`) + notify(`Could not edit post: ${error.message}`); redirect('/posts'); refresh(); }; @@ -2226,7 +2229,7 @@ const PostEdit = props => { if (error.code == 123) { notify('Could not save changes: concurrent edition in progress', 'warning'); } else { - notify('ra.notification.http_error', 'warning') + notify('ra.notification.http_error', 'warning'); } redirect('list', props.basePath); } diff --git a/docs/List.md b/docs/List.md index 9d903abb396..fc1659b79c6 100644 --- a/docs/List.md +++ b/docs/List.md @@ -489,7 +489,7 @@ const CustomResetViewsButton = ({ selectedIds }) => { onSuccess: () => { refresh(); - notify('Posts updated'); -+ notify('Posts updated', 'info', '{}, true); // the last argument forces the display of 'undo' in the notification ++ notify('Posts updated', { undoable: true }); // the last argument forces the display of 'undo' in the notification unselectAll('posts'); }, onFailure: error => notify('Error: posts not updated', 'warning'), diff --git a/packages/ra-core/src/sideEffect/useNotify.spec.tsx b/packages/ra-core/src/sideEffect/useNotify.spec.tsx index 77135422cf9..5d64400b9de 100644 --- a/packages/ra-core/src/sideEffect/useNotify.spec.tsx +++ b/packages/ra-core/src/sideEffect/useNotify.spec.tsx @@ -8,13 +8,12 @@ const Notification = ({ message, undoable = false, autoHideDuration = 4000, - multiLine = true, + multiLine = false, shortSignature = false, }) => { const notify = useNotify(); useEffect(() => { if (shortSignature) { - // @ts-ignore notify(message, { type, undoable, @@ -48,4 +47,17 @@ describe('useNotify', () => { expect(dispatch).toHaveBeenCalledTimes(1); }); + + it('should show a notification message of type "warning"', () => { + const { dispatch } = renderWithRedux( + + ); + + expect(dispatch).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/ra-core/src/sideEffect/useNotify.ts b/packages/ra-core/src/sideEffect/useNotify.ts index 495f7c71d79..c3e7f593093 100644 --- a/packages/ra-core/src/sideEffect/useNotify.ts +++ b/packages/ra-core/src/sideEffect/useNotify.ts @@ -3,6 +3,7 @@ import { useDispatch } from 'react-redux'; import { showNotification, NotificationType, + NotificationOptions, } from '../actions/notificationActions'; /** @@ -25,20 +26,27 @@ const useNotify = () => { return useCallback( ( message: string, - type: NotificationType = 'info', + type?: + | NotificationType + | (NotificationOptions & { type: NotificationType }), messageArgs: any = {}, undoable: boolean = false, autoHideDuration?: number, multiLine?: boolean ) => { - dispatch( - showNotification(message, type, { - messageArgs, - undoable, - autoHideDuration, - multiLine, - }) - ); + if (typeof type === 'string') { + dispatch( + showNotification(message, type || 'info', { + messageArgs, + undoable, + autoHideDuration, + multiLine, + }) + ); + } else { + const { type: messageType, ...options } = type; + dispatch(showNotification(message, messageType, options)); + } }, [dispatch] ); From e4cc5481a0abe2d6ef4346b92b99aee6af9f5279 Mon Sep 17 00:00:00 2001 From: asvarcas Date: Wed, 13 Oct 2021 12:27:51 -0300 Subject: [PATCH 2/7] Remove not related changes --- packages/ra-core/src/actions/notificationActions.ts | 2 -- packages/ra-core/src/sideEffect/useNotify.ts | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/ra-core/src/actions/notificationActions.ts b/packages/ra-core/src/actions/notificationActions.ts index 52bd6e8ad84..f9beecc3716 100644 --- a/packages/ra-core/src/actions/notificationActions.ts +++ b/packages/ra-core/src/actions/notificationActions.ts @@ -7,8 +7,6 @@ export interface NotificationOptions { autoHideDuration?: number; // Arguments used to translate the message messageArgs?: any; - // If true, the notification shows the message in multiple lines - multiLine?: boolean; // If true, the notification shows an Undo button undoable?: boolean; } diff --git a/packages/ra-core/src/sideEffect/useNotify.ts b/packages/ra-core/src/sideEffect/useNotify.ts index c3e7f593093..122ef8c1bf2 100644 --- a/packages/ra-core/src/sideEffect/useNotify.ts +++ b/packages/ra-core/src/sideEffect/useNotify.ts @@ -31,8 +31,7 @@ const useNotify = () => { | (NotificationOptions & { type: NotificationType }), messageArgs: any = {}, undoable: boolean = false, - autoHideDuration?: number, - multiLine?: boolean + autoHideDuration?: number ) => { if (typeof type === 'string') { dispatch( @@ -40,7 +39,6 @@ const useNotify = () => { messageArgs, undoable, autoHideDuration, - multiLine, }) ); } else { From 65b3d30bc96dbc00fbd1a0d6c4165537016dfbb8 Mon Sep 17 00:00:00 2001 From: asvarcas Date: Wed, 13 Oct 2021 13:09:47 -0300 Subject: [PATCH 3/7] Fix not related changes --- packages/ra-core/src/sideEffect/useNotify.spec.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/ra-core/src/sideEffect/useNotify.spec.tsx b/packages/ra-core/src/sideEffect/useNotify.spec.tsx index 5d64400b9de..de222b813b4 100644 --- a/packages/ra-core/src/sideEffect/useNotify.spec.tsx +++ b/packages/ra-core/src/sideEffect/useNotify.spec.tsx @@ -18,16 +18,15 @@ const Notification = ({ type, undoable, autoHideDuration, - multiLine, }); } else { - notify(message, type, {}, undoable, autoHideDuration, multiLine); + notify(message, type, {}, undoable, autoHideDuration); } }, [ message, undoable, autoHideDuration, - multiLine, + shortSignature, shortSignature, type, notify, From cc7b55ca29b032b565ba2b251af7f840f087c5e3 Mon Sep 17 00:00:00 2001 From: asvarcas Date: Wed, 13 Oct 2021 14:07:30 -0300 Subject: [PATCH 4/7] Added deprecated warning --- packages/ra-core/src/sideEffect/useNotify.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ra-core/src/sideEffect/useNotify.ts b/packages/ra-core/src/sideEffect/useNotify.ts index 122ef8c1bf2..15d7a5ceec9 100644 --- a/packages/ra-core/src/sideEffect/useNotify.ts +++ b/packages/ra-core/src/sideEffect/useNotify.ts @@ -5,6 +5,7 @@ import { NotificationType, NotificationOptions, } from '../actions/notificationActions'; +import warning from '../util/warning'; /** * Hook for Notification Side Effect @@ -34,6 +35,10 @@ const useNotify = () => { autoHideDuration?: number ) => { if (typeof type === 'string') { + warning( + true, + 'This way of calling useNotify callback is deprecated. Please use the new syntax passing notify("[Your message]", { ...restOfArguments })' + ); dispatch( showNotification(message, type || 'info', { messageArgs, From 92e52cb65c4f7d7d8cc7eadd872288a2f8ca2b15 Mon Sep 17 00:00:00 2001 From: asvarcas Date: Wed, 13 Oct 2021 16:09:19 -0300 Subject: [PATCH 5/7] Updated notification callback examples --- UPGRADE.md | 2 +- docs/Actions.md | 16 ++++++++-------- docs/CreateEdit.md | 18 ++++++++---------- docs/List.md | 6 +++--- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/UPGRADE.md b/UPGRADE.md index 25ca446afdb..baba3a4bbee 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -469,7 +469,7 @@ const ExportButton = ({ sort, filter, maxResults = 1000, resource }) => { const payload = { sort, filter, pagination: { page: 1, perPage: maxResults }} const handleClick = dataProvider.getList(resource, payload) .then(({ data }) => jsonExport(data, (err, csv) => downloadCSV(csv, resource))) - .catch(error => notify('ra.notification.http_error', 'warning')); + .catch(error => notify('ra.notification.http_error', { type: 'warning'})); return ( ; }; @@ -803,7 +803,7 @@ const ApproveButton = ({ record }) => { redirect('/comments'); notify('Comment approved'); }, - onFailure: (error) => notify(`Comment approval error: ${error.message}`, 'warning'), + onFailure: (error) => notify(`Comment approval error: ${error.message}`, { type: 'warning' }), } ); return