Skip to content

Commit fbbfb9c

Browse files
committed
story and test for useUpdateMany
1 parent 34fbeb5 commit fbbfb9c

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

packages/ra-core/src/dataProvider/useUpdateMany.spec.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
Params,
1818
UndefinedValues,
1919
WithMiddlewares,
20+
InvalidateList,
2021
} from './useUpdateMany.stories';
2122

2223
describe('useUpdateMany', () => {
@@ -525,6 +526,14 @@ describe('useUpdateMany', () => {
525526
'[{"id":1,"title":"world"},{"id":2,"title":"world"}]'
526527
); // and not [{"title":"world"},{"title":"world"}]
527528
});
529+
530+
it('invalidates getList query dataProvider resolves in undoable mode', async () => {
531+
render(<InvalidateList mutationMode="undoable" />);
532+
fireEvent.click(await screen.findByText('Update'));
533+
await screen.findByText('resources.posts.notifications.updated');
534+
fireEvent.click(screen.getByText('Close'));
535+
await screen.findByText('1: Hello updated');
536+
});
528537
});
529538

530539
describe('middlewares', () => {

packages/ra-core/src/dataProvider/useUpdateMany.stories.tsx

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import * as React from 'react';
22
import { QueryClient, useIsMutating } from '@tanstack/react-query';
33

4-
import { CoreAdminContext } from '../core';
4+
import { CoreAdmin, CoreAdminContext, Resource } from '../core';
55
import { useUpdateMany } from './useUpdateMany';
66
import { useGetList } from './useGetList';
77
import { useState } from 'react';
88
import { useGetOne } from './useGetOne';
99
import { useTakeUndoableMutation } from './undo';
1010
import type { DataProvider, MutationMode as MutationModeType } from '../types';
11+
import fakeRestDataProvider from 'ra-data-fakerest';
12+
import { TestMemoryRouter, useRedirect } from '../routing';
13+
import { useNotificationContext, useNotify } from '../notification';
14+
import { EditBase, ListBase, RecordsIterator } from '../controller';
1115

1216
export default { title: 'ra-core/dataProvider/useUpdateMany' };
1317

@@ -309,3 +313,125 @@ const ParamsCore = () => {
309313
</>
310314
);
311315
};
316+
317+
const Notification = () => {
318+
const { notifications, resetNotifications } = useNotificationContext();
319+
const takeMutation = useTakeUndoableMutation();
320+
321+
return notifications.length > 0 ? (
322+
<>
323+
<div>{notifications[0].message}</div>
324+
<div style={{ display: 'flex', gap: '16px' }}>
325+
<button
326+
onClick={() => {
327+
if (notifications[0].notificationOptions?.undoable) {
328+
const mutation = takeMutation();
329+
if (mutation) {
330+
mutation({ isUndo: false });
331+
}
332+
}
333+
resetNotifications();
334+
}}
335+
>
336+
Close
337+
</button>
338+
</div>
339+
</>
340+
) : null;
341+
};
342+
343+
const UpdateButton = ({ mutationMode }: { mutationMode: MutationModeType }) => {
344+
const notify = useNotify();
345+
const redirect = useRedirect();
346+
const [updateMany, { isPending }] = useUpdateMany();
347+
const handleClick = () => {
348+
updateMany(
349+
'posts',
350+
{
351+
ids: [1],
352+
data: { title: 'Hello updated' },
353+
},
354+
{
355+
mutationMode,
356+
onSuccess: () => {
357+
// Show undoable notification like controllers do
358+
notify('resources.posts.notifications.updated', {
359+
type: 'info',
360+
undoable: mutationMode === 'undoable',
361+
});
362+
// Redirect to list after mutation succeeds
363+
redirect('list', 'posts');
364+
},
365+
}
366+
);
367+
};
368+
return (
369+
<button onClick={handleClick} disabled={isPending}>
370+
Update
371+
</button>
372+
);
373+
};
374+
375+
export const InvalidateList = ({
376+
mutationMode,
377+
}: {
378+
mutationMode: MutationModeType;
379+
}) => {
380+
const dataProvider = fakeRestDataProvider(
381+
{
382+
posts: [
383+
{ id: 1, title: 'Hello' },
384+
{ id: 2, title: 'World' },
385+
],
386+
},
387+
process.env.NODE_ENV !== 'test',
388+
process.env.NODE_ENV === 'test' ? 10 : 1000
389+
);
390+
391+
return (
392+
<TestMemoryRouter initialEntries={['/posts/1']}>
393+
<CoreAdmin dataProvider={dataProvider}>
394+
<Resource
395+
name="posts"
396+
edit={
397+
<EditBase>
398+
<div>
399+
<h1>Edit Post</h1>
400+
<UpdateButton mutationMode={mutationMode} />
401+
</div>
402+
</EditBase>
403+
}
404+
list={
405+
<ListBase loading={<p>Loading...</p>}>
406+
<RecordsIterator
407+
render={record => (
408+
<div
409+
style={{
410+
display: 'flex',
411+
gap: '8px',
412+
alignItems: 'center',
413+
}}
414+
>
415+
{record.id}: {record.title}
416+
</div>
417+
)}
418+
/>
419+
<Notification />
420+
</ListBase>
421+
}
422+
/>
423+
</CoreAdmin>
424+
</TestMemoryRouter>
425+
);
426+
};
427+
InvalidateList.args = {
428+
mutationMode: 'undoable',
429+
};
430+
InvalidateList.argTypes = {
431+
mutationMode: {
432+
control: {
433+
type: 'select',
434+
},
435+
options: ['pessimistic', 'optimistic', 'undoable'],
436+
},
437+
};

0 commit comments

Comments
 (0)